diff options
-rw-r--r-- | src/mm-plugin-manager.c | 742 |
1 files changed, 271 insertions, 471 deletions
diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c index 0b637f5d..2d6ba835 100644 --- a/src/mm-plugin-manager.c +++ b/src/mm-plugin-manager.c @@ -11,8 +11,9 @@ * GNU General Public License for more details: * * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2009 - 2011 Red Hat, Inc. - * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org> + * Copyright (C) 2009 - 2012 Red Hat, Inc. + * Copyright (C) 2011 - 2012 Aleksander Morgado <aleksander@gnu.org> + * Copyright (C) 2012 Google, Inc. */ #include <string.h> @@ -29,7 +30,7 @@ #include "mm-log.h" /* Default time to defer probing checks */ -#define SUPPORTS_DEFER_TIMEOUT_SECS 3 +#define DEFER_TIMEOUT_SECS 3 /* Time to wait for other ports to appear once the first port is exposed */ #define MIN_PROBING_TIME_SECS 2 @@ -44,224 +45,231 @@ struct _MMPluginManagerPrivate { /* The list of plugins. It is loaded once when the program starts, and the * list is NOT expected to change after that. */ GSList *plugins; - - /* Hash table to keep track of support tasks, using physical path of the - * device as key (which means that more than one tasks may be associated - * to the same key if the modem happens to show more than one port). - * The data in each HT item will be SupportsInfoList (not a GSList directly, - * as we want to be able to modify the list without replacing items with - * the HT API, which also replaces keys). */ - GHashTable *supports; }; /*****************************************************************************/ +/* Find device support */ -/* List of support infos associated to the same physical device */ -typedef struct { - GSList *info_list; -} SupportsInfoList; - -/* Context of the task looking for best port support */ typedef struct { MMPluginManager *self; + MMDevice *device; GSimpleAsyncResult *result; - /* Input context */ - gchar *subsys; - gchar *name; - gchar *physdev_path; - MMBaseModem *existing; - /* Current context */ - MMPlugin *suggested_plugin; + guint timeout_id; + gulong grabbed_id; + gulong released_id; + + GList *running_probes; +} FindDeviceSupportContext; + +typedef struct { + FindDeviceSupportContext *parent_ctx; + GUdevDevice *port; + GSList *current; - guint source_id; - gboolean defer_until_suggested; - /* Output context */ MMPlugin *best_plugin; -} SupportsInfo; + MMPlugin *suggested_plugin; + guint defer_id; + gboolean defer_until_suggested; +} PortProbeContext; + +static void port_probe_context_step (PortProbeContext *port_probe_ctx); +static void suggest_port_probe_result (FindDeviceSupportContext *ctx, + MMPlugin *suggested_plugin); static void -supports_info_free (SupportsInfo *info) +port_probe_context_free (PortProbeContext *ctx) { - if (!info) - return; + g_assert (ctx->defer_id == 0); - /* There shouldn't be any ongoing supports operation */ - g_assert (info->current == NULL); + if (ctx->best_plugin) + g_object_unref (ctx->best_plugin); + if (ctx->suggested_plugin) + g_object_unref (ctx->suggested_plugin); + g_object_unref (ctx->port); + g_slice_free (PortProbeContext, ctx); +} - /* There shouldn't be any scheduled source */ - g_assert (info->source_id == 0); +static void +find_device_support_context_complete_and_free (FindDeviceSupportContext *ctx) +{ + g_assert (ctx->timeout_id == 0); - if (info->existing) - g_object_unref (info->existing); + /* Set async operation result */ + if (!mm_device_peek_plugin (ctx->device)) { + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_UNSUPPORTED, + "not supported by any plugin"); + } else { + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + } - g_object_unref (info->result); - g_free (info->subsys); - g_free (info->name); - g_free (info->physdev_path); - g_free (info); + g_simple_async_result_complete (ctx->result); + + g_signal_handler_disconnect (ctx->device, ctx->grabbed_id); + g_signal_handler_disconnect (ctx->device, ctx->released_id); + + g_warn_if_fail (ctx->running_probes == NULL); + + g_object_unref (ctx->result); + g_object_unref (ctx->device); + g_object_unref (ctx->self); + g_slice_free (FindDeviceSupportContext, ctx); } -static void -supports_info_list_free (SupportsInfoList *list) +gboolean +mm_plugin_manager_find_device_support_finish (MMPluginManager *self, + GAsyncResult *result, + GError **error) { - g_slist_foreach (list->info_list, - (GFunc)supports_info_free, - NULL); - g_slist_free (list->info_list); - g_free (list); + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); } static void -add_supports_info (MMPluginManager *self, - SupportsInfo *info) +port_probe_context_finished (PortProbeContext *port_probe_ctx) { - SupportsInfoList *list; - - list = g_hash_table_lookup (self->priv->supports, - info->physdev_path); - if (!list) { - list = g_malloc0 (sizeof (SupportsInfoList)); - g_hash_table_insert (self->priv->supports, - g_strdup (info->physdev_path), - list); - } + FindDeviceSupportContext *ctx = port_probe_ctx->parent_ctx; - list->info_list = g_slist_append (list->info_list, info); -} + if (!port_probe_ctx->best_plugin) { + gboolean cancel_remaining; + GList *l; + + mm_dbg ("(%s/%s): not supported by any plugin", + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); + + /* If this is the last valid probe which was running (i.e. the last one + * not being deferred-until-suggested), cancel all remaining ones. */ + cancel_remaining = TRUE; + for (l = ctx->running_probes; l; l = g_list_next (l)) { + PortProbeContext *other = l->data; + + /* Do not cancel anything if we find at least one probe which is not + * waiting for the suggested plugin */ + if (other != port_probe_ctx && !other->defer_until_suggested) { + cancel_remaining = FALSE; + break; + } + } -static void -remove_supports_info (MMPluginManager *self, - SupportsInfo *info) -{ - SupportsInfoList *list; + if (cancel_remaining) + /* Set a NULL suggested plugin, will cancel the probes */ + suggest_port_probe_result (ctx, NULL); - list = g_hash_table_lookup (self->priv->supports, - info->physdev_path); - g_assert (list != NULL); - g_assert (list->info_list != NULL); + } else { + /* Notify the plugin to the device, if this is the first port probing + * result we got. */ + if (!mm_device_peek_plugin (ctx->device)) { + mm_dbg ("(%s/%s): found best plugin (%s) for device (%s)", + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port), + mm_plugin_get_name (port_probe_ctx->best_plugin), + mm_device_get_path (ctx->device)); + mm_device_set_plugin (ctx->device, port_probe_ctx->best_plugin); - list->info_list = g_slist_remove (list->info_list, info); + /* Suggest this plugin also to other port probes */ + suggest_port_probe_result (ctx, port_probe_ctx->best_plugin); + } + /* Warn if the best plugin found for this port differs from the + * best plugin found for the the first probed port. */ + else if (!g_str_equal (mm_plugin_get_name (mm_device_peek_plugin (ctx->device)), + mm_plugin_get_name (port_probe_ctx->best_plugin))) { + mm_warn ("(%s/%s): plugin mismatch error (expected: '%s', got: '%s')", + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port), + mm_plugin_get_name (mm_device_peek_plugin (ctx->device)), + mm_plugin_get_name (port_probe_ctx->best_plugin)); + } + } - /* If it was the last info for the given physical path, - * also remove it */ - if (!list->info_list) - g_hash_table_remove (self->priv->supports, - info->physdev_path); + /* Remove us from the list of running probes */ + g_assert (g_list_find (ctx->running_probes, port_probe_ctx) != NULL); + ctx->running_probes = g_list_remove (ctx->running_probes, port_probe_ctx); + port_probe_context_free (port_probe_ctx); - /* Note that we just remove it from the list, we don't free it */ -} + /* If there are running probes around, wait for them to finish */ + if (ctx->running_probes != NULL) + return; -/*****************************************************************************/ -/* Find port support */ + /* If we didn't use the minimum probing time, wait for it to finish */ + if (ctx->timeout_id > 0) + return; -static gboolean find_port_support_idle (SupportsInfo *info); + /* If we just finished the last running probe, we can now finish the device + * support check */ + find_device_support_context_complete_and_free (ctx); +} -static void -suggest_supports_info_result (MMPluginManager *self, - const gchar *physdev_path, - MMPlugin *suggested_plugin) +static gboolean +deferred_support_check_idle (PortProbeContext *port_probe_ctx) { - SupportsInfoList *list; - GSList *l; - - list = g_hash_table_lookup (self->priv->supports, - physdev_path); + port_probe_ctx->defer_id = 0; + port_probe_context_step (port_probe_ctx); + return FALSE; +} - if (!list) - return; +static void +suggest_port_probe_result (FindDeviceSupportContext *ctx, + MMPlugin *suggested_plugin) +{ + GList *l; - /* Look for support infos on the same physical path */ - for (l = list->info_list; - l; - l = g_slist_next (l)) { - SupportsInfo *info = l->data; + for (l = ctx->running_probes; l; l = g_list_next (l)) { + PortProbeContext *port_probe_ctx = l->data; - if (!info->best_plugin && - !info->suggested_plugin) { + if (!port_probe_ctx->best_plugin && + !port_probe_ctx->suggested_plugin) { /* TODO: Cancel probing in the port if the plugin being * checked right now is not the one being suggested. */ - mm_dbg ("(%s): (%s) suggested plugin for port", - mm_plugin_get_name (suggested_plugin), - info->name); - info->suggested_plugin = suggested_plugin; + if (suggested_plugin) { + mm_dbg ("(%s): (%s/%s) suggested plugin for port", + mm_plugin_get_name (suggested_plugin), + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); + port_probe_ctx->suggested_plugin = g_object_ref (suggested_plugin); + } /* If we got a task deferred until a suggestion comes, * complete it */ - if (info->defer_until_suggested) { - mm_dbg ("(%s): (%s) deferred task completed, got suggested plugin", - mm_plugin_get_name (suggested_plugin), - info->name); + if (port_probe_ctx->defer_until_suggested) { + if (suggested_plugin) + mm_dbg ("(%s): (%s/%s) deferred task completed, got suggested plugin", + mm_plugin_get_name (suggested_plugin), + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); + else + mm_dbg ("(%s/%s) deferred task cancelled, no suggested plugin", + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); + /* Schedule checking support, which will end the operation */ - info->best_plugin = info->suggested_plugin; - info->current = NULL; - info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, - info); + port_probe_ctx->best_plugin = g_object_ref (port_probe_ctx->suggested_plugin); + port_probe_ctx->current = NULL; + g_assert (port_probe_ctx->defer_id == 0); + port_probe_ctx->defer_id = g_idle_add ((GSourceFunc)deferred_support_check_idle, + port_probe_ctx); } } } } static void -cancel_all_deferred_supports_info (MMPluginManager *self, - const gchar *physdev_path) -{ - gboolean abort_cancel = FALSE; - SupportsInfoList *list; - GSList *l; - - list = g_hash_table_lookup (self->priv->supports, - physdev_path); - - if (!list) - return; - - /* Look for support infos on the same physical path. - * We need to look for tasks being deferred until suggested and count - * them. */ - for (l = list->info_list; - l && !abort_cancel; - l = g_slist_next (l)) { - SupportsInfo *info = l->data; - - if (!info->defer_until_suggested) - abort_cancel = TRUE; - } - - if (abort_cancel) - return; - - /* If all remaining tasks were deferred until suggested, we need to - * cancel them completely */ - - for (l = list->info_list; l; l = g_slist_next (l)) { - SupportsInfo *info = l->data; - - mm_dbg ("(%s) deferred task aborted, no suggested plugin set", - info->name); - /* Schedule checking support, which will end the operation */ - info->current = NULL; - info->best_plugin = NULL; - info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, info); - } -} - -static void -supports_port_ready_cb (MMPlugin *plugin, - GAsyncResult *result, - SupportsInfo *info) +plugin_supports_port_ready (MMPlugin *plugin, + GAsyncResult *result, + PortProbeContext *port_probe_ctx) { MMPluginSupportsResult support_result; GError *error = NULL; /* Get supports check results */ - support_result = mm_plugin_supports_port_finish (plugin, - result, - &error); + support_result = mm_plugin_supports_port_finish (plugin, result, &error); + if (error) { - mm_warn ("(%s): (%s) error when checking support: '%s'", + mm_warn ("(%s): (%s/%s) error when checking support: '%s'", mm_plugin_get_name (plugin), - info->name, + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port), error->message); g_error_free (error); } @@ -269,334 +277,127 @@ supports_port_ready_cb (MMPlugin *plugin, switch (support_result) { case MM_PLUGIN_SUPPORTS_PORT_SUPPORTED: /* Found a best plugin */ - info->best_plugin = plugin; + port_probe_ctx->best_plugin = g_object_ref (plugin); - if (info->suggested_plugin && - info->suggested_plugin != plugin) { + if (port_probe_ctx->suggested_plugin && + port_probe_ctx->suggested_plugin != plugin) { /* The last plugin we tried said it supported this port, but it * doesn't correspond with the one we're being suggested. */ g_warn_if_reached (); } - mm_dbg ("(%s): (%s) found best plugin for port", - mm_plugin_get_name (info->best_plugin), - info->name); - info->current = NULL; + mm_dbg ("(%s): (%s/%s) found best plugin for port", + mm_plugin_get_name (port_probe_ctx->best_plugin), + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); + port_probe_ctx->current = NULL; + + /* Step, which will end the port probe operation */ + port_probe_context_step (port_probe_ctx); + return; - /* Schedule checking support, which will end the operation */ - info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, - info); - break; case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED: - if (info->suggested_plugin) { - if (info->suggested_plugin == plugin) { + if (port_probe_ctx->suggested_plugin) { + if (port_probe_ctx->suggested_plugin == plugin) { /* If the plugin that just completed the support check claims * not to support this port, but this plugin is clearly the * right plugin since it claimed this port's physical modem, * just drop the port. */ mm_dbg ("(%s/%s): ignoring port unsupported by physical modem's plugin", - info->subsys, - info->name); - info->best_plugin = NULL; - info->current = NULL; + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); + port_probe_ctx->best_plugin = NULL; + port_probe_ctx->current = NULL; } else { /* The last plugin we tried is NOT the one we got suggested, so * directly check support with the suggested plugin. If we * already checked its support, it won't be checked again. */ - info->current = g_slist_find (info->current, - info->suggested_plugin); + port_probe_ctx->current = g_slist_find (port_probe_ctx->current, + port_probe_ctx->suggested_plugin); } } else { /* If the plugin knows it doesn't support the modem, just keep on * checking the next plugin. */ - info->current = g_slist_next (info->current); + port_probe_ctx->current = g_slist_next (port_probe_ctx->current); } - info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, - info); - break; + + /* Step */ + port_probe_context_step (port_probe_ctx); + return; + case MM_PLUGIN_SUPPORTS_PORT_DEFER: /* Try with the suggested one after being deferred */ - if (info->suggested_plugin) { - mm_dbg ("(%s): (%s) deferring support check, suggested: %s", - mm_plugin_get_name (MM_PLUGIN (info->current->data)), - info->name, - mm_plugin_get_name (MM_PLUGIN (info->suggested_plugin))); - info->current = g_slist_find (info->current, - info->suggested_plugin); + if (port_probe_ctx->suggested_plugin) { + mm_dbg ("(%s): (%s/%s) deferring support check, suggested: %s", + mm_plugin_get_name (MM_PLUGIN (port_probe_ctx->current->data)), + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port), + mm_plugin_get_name (MM_PLUGIN (port_probe_ctx->suggested_plugin))); + port_probe_ctx->current = g_slist_find (port_probe_ctx->current, + port_probe_ctx->suggested_plugin); } else { - mm_dbg ("(%s): (%s) deferring support check", - mm_plugin_get_name (MM_PLUGIN (info->current->data)), - info->name); + mm_dbg ("(%s): (%s/%s) deferring support check", + mm_plugin_get_name (MM_PLUGIN (port_probe_ctx->current->data)), + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); } + /* Schedule checking support */ - info->source_id = g_timeout_add_seconds (SUPPORTS_DEFER_TIMEOUT_SECS, - (GSourceFunc)find_port_support_idle, - info); - break; + port_probe_ctx->defer_id = g_timeout_add_seconds (DEFER_TIMEOUT_SECS, + (GSourceFunc)deferred_support_check_idle, + port_probe_ctx); + return; + case MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED: /* If we arrived here and we already have a plugin suggested, use it */ - if (info->suggested_plugin) { - mm_dbg ("(%s): (%s) task completed, got suggested plugin", - mm_plugin_get_name (info->suggested_plugin), - info->name); + if (port_probe_ctx->suggested_plugin) { + mm_dbg ("(%s): (%s/%s) task completed, got suggested plugin", + mm_plugin_get_name (port_probe_ctx->suggested_plugin), + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); /* Schedule checking support, which will end the operation */ - info->best_plugin = info->suggested_plugin; - info->current = NULL; - info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, - info); - } else { - /* We are deferred until a suggested plugin is given. If last supports task - * of a given device is finished without finding a best plugin, this task - * will get finished reporting unsupported. */ - mm_dbg ("(%s) deferring support check until result suggested", - info->name); - info->defer_until_suggested = TRUE; - } - break; - } -} - -static gboolean -find_port_support_idle (SupportsInfo *info) -{ - info->source_id = 0; - - /* Already checked all plugins? */ - if (!info->current) { - /* Report best plugin in asynchronous result (could be none) */ - if (info->best_plugin) - g_simple_async_result_set_op_res_gpointer ( - info->result, - g_object_ref (info->best_plugin), - (GDestroyNotify)g_object_unref); - else - g_simple_async_result_set_op_res_gpointer ( - info->result, - NULL, - NULL); - - /* We are only giving the plugin as result, so we can now safely remove - * the supports info from the manager. Always untrack the supports info - * before completing the operation. */ - remove_supports_info (info->self, info); - - /* We are reporting a best plugin found to a port. We can now - * 'suggest' this same plugin to other ports of the same device. */ - if (info->best_plugin) - suggest_supports_info_result (info->self, - info->physdev_path, - info->best_plugin); - /* If ending without a best plugin, we need to cancel all probing tasks - * that got deferred until suggested. */ - else - cancel_all_deferred_supports_info (info->self, - info->physdev_path); - - g_simple_async_result_complete (info->result); - - supports_info_free (info); - return FALSE; - } - - /* Ask the current plugin to check support of this port */ - mm_plugin_supports_port (MM_PLUGIN (info->current->data), - info->subsys, - info->name, - info->physdev_path, - info->existing, - (GAsyncReadyCallback)supports_port_ready_cb, - info); - return FALSE; -} - -static MMPlugin * -find_port_support_finish (MMPluginManager *self, - GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (MM_IS_PLUGIN_MANAGER (self), NULL); - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); - - /* Propagate error, if any */ - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return NULL; - - /* Return the plugin found, if any */ - return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); -} - -static void -find_port_support (MMPluginManager *self, - const gchar *subsys, - const gchar *name, - const gchar *physdev_path, - MMPlugin *suggested_plugin, - MMBaseModem *existing, - GAsyncReadyCallback callback, - gpointer user_data) -{ - SupportsInfo *info; - - g_return_if_fail (MM_IS_PLUGIN_MANAGER (self)); - - /* Setup supports info */ - info = g_malloc0 (sizeof (SupportsInfo)); - info->self = self; /* SupportsInfo lives as long as self lives */ - info->subsys = g_strdup (subsys); - info->name = g_strdup (name); - info->physdev_path = g_strdup (physdev_path); - info->suggested_plugin = suggested_plugin; - if (existing) - info->existing = g_object_ref (existing); - info->result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - find_port_support); - - /* Set first plugin to check */ - info->current = self->priv->plugins; - - /* If we got one suggested, it will be the first one */ - if (info->suggested_plugin) { - info->current = g_slist_find (info->current, - info->suggested_plugin); - } - - /* We will keep track of the supports info internally. - * Ownership of the supports info will belong to the manager now. */ - add_supports_info (self, info); - - /* Schedule the processing of the supports task in an idle */ - info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, - info); -} - -/*****************************************************************************/ -/* Find device support */ - -typedef struct { - MMPluginManager *self; - MMDevice *device; - GSimpleAsyncResult *result; - guint timeout_id; - gulong grabbed_id; - gulong released_id; - - GList *running_probes; -} FindDeviceSupportContext; - -typedef struct { - GUdevDevice *port; - FindDeviceSupportContext *parent_ctx; -} PortProbeContext; - -static void -port_probe_context_free (PortProbeContext *ctx) -{ - g_object_unref (ctx->port); - g_slice_free (PortProbeContext, ctx); -} + port_probe_ctx->best_plugin = g_object_ref (port_probe_ctx->suggested_plugin); + port_probe_ctx->current = NULL; -static void -find_device_support_context_complete_and_free (FindDeviceSupportContext *ctx) -{ - g_assert (ctx->timeout_id == 0); + port_probe_context_step (port_probe_ctx); + return; + } - /* Set async operation result */ - if (!mm_device_peek_plugin (ctx->device)) { - g_simple_async_result_set_error (ctx->result, - MM_CORE_ERROR, - MM_CORE_ERROR_UNSUPPORTED, - "not supported by any plugin"); - } else { - g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + /* We are deferred until a suggested plugin is given. If last supports task + * of a given device is finished without finding a best plugin, this task + * will get finished reporting unsupported. */ + mm_dbg ("(%s/%s) deferring support check until result suggested", + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port)); + port_probe_ctx->defer_until_suggested = TRUE; + return; } - - g_simple_async_result_complete (ctx->result); - - g_signal_handler_disconnect (ctx->device, ctx->grabbed_id); - g_signal_handler_disconnect (ctx->device, ctx->released_id); - - g_warn_if_fail (ctx->running_probes == NULL); - - g_object_unref (ctx->result); - g_object_unref (ctx->device); - g_object_unref (ctx->self); - g_slice_free (FindDeviceSupportContext, ctx); -} - -gboolean -mm_plugin_manager_find_device_support_finish (MMPluginManager *self, - GAsyncResult *result, - GError **error) -{ - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); } static void -find_port_support_ready (MMPluginManager *self, - GAsyncResult *result, - PortProbeContext *port_probe_ctx) +port_probe_context_step (PortProbeContext *port_probe_ctx) { FindDeviceSupportContext *ctx = port_probe_ctx->parent_ctx; - GError *error = NULL; - MMPlugin *best_plugin; - - best_plugin = find_port_support_finish (self, result, &error); - if (!best_plugin) { - if (error) { - mm_warn ("(%s/%s): error checking support: '%s'", - g_udev_device_get_subsystem (port_probe_ctx->port), - g_udev_device_get_name (port_probe_ctx->port), - error->message); - g_error_free (error); - } else { - mm_dbg ("(%s/%s): not supported by any plugin", - g_udev_device_get_subsystem (port_probe_ctx->port), - g_udev_device_get_name (port_probe_ctx->port)); - } - } else { - /* Found a best plugin for the port */ - - if (!mm_device_peek_plugin (ctx->device)) { - mm_dbg ("(%s/%s): found best plugin (%s) for device (%s)", - g_udev_device_get_subsystem (port_probe_ctx->port), - g_udev_device_get_name (port_probe_ctx->port), - mm_plugin_get_name (best_plugin), - mm_device_get_path (ctx->device)); - mm_device_set_plugin (ctx->device, best_plugin); - } else if (!g_str_equal (mm_plugin_get_name (mm_device_peek_plugin (ctx->device)), - mm_plugin_get_name (best_plugin))) { - /* Warn if the best plugin found for this port differs from the - * best plugin found for the the first grabbed port */ - mm_warn ("(%s/%s): plugin mismatch error (expected: '%s', got: '%s')", - g_udev_device_get_subsystem (port_probe_ctx->port), - g_udev_device_get_name (port_probe_ctx->port), - mm_plugin_get_name (mm_device_peek_plugin (ctx->device)), - mm_plugin_get_name (best_plugin)); - } - } - - g_assert (g_list_find (ctx->running_probes, port_probe_ctx) != NULL); - ctx->running_probes = g_list_remove (ctx->running_probes, port_probe_ctx); - port_probe_context_free (port_probe_ctx); - - /* If there are running probes around, wait for them to finish */ - if (ctx->running_probes != NULL) - return; - /* If we didn't use the minimum probing time, wait for it to finish */ - if (ctx->timeout_id > 0) + /* Already checked all plugins? */ + if (!port_probe_ctx->current) { + port_probe_context_finished (port_probe_ctx); return; + } - /* If we just finished the last running probe, we can now finish the device - * support check */ - find_device_support_context_complete_and_free (ctx); + /* Ask the current plugin to check support of this port */ + mm_plugin_supports_port (MM_PLUGIN (port_probe_ctx->current->data), + g_udev_device_get_subsystem (port_probe_ctx->port), + g_udev_device_get_name (port_probe_ctx->port), + mm_device_get_path (ctx->device), + NULL, /* TODO: existing modem */ + (GAsyncReadyCallback)plugin_supports_port_ready, + port_probe_ctx); } static void @@ -612,22 +413,23 @@ device_port_grabbed_cb (MMDevice *device, /* Launch probing task on this port with the first plugin of the list */ port_probe_ctx = g_slice_new0 (PortProbeContext); - port_probe_ctx->port = g_object_ref (port); port_probe_ctx->parent_ctx = ctx; + port_probe_ctx->port = g_object_ref (port); + + /* Set first plugin to check */ + port_probe_ctx->current = ctx->self->priv->plugins; + + /* If we got one suggested, it will be the first one */ + port_probe_ctx->suggested_plugin = mm_device_get_plugin (device); + if (port_probe_ctx->suggested_plugin) + port_probe_ctx->current = g_slist_find (port_probe_ctx->current, + port_probe_ctx->suggested_plugin); /* Set as running */ ctx->running_probes = g_list_prepend (ctx->running_probes, port_probe_ctx); /* Launch supports check in the Plugin Manager */ - find_port_support ( - ctx->self, - g_udev_device_get_subsystem (port_probe_ctx->port), - g_udev_device_get_name (port_probe_ctx->port), - mm_device_get_path (ctx->device), - NULL, /* plugin */ - NULL, /* modem */ - (GAsyncReadyCallback)find_port_support_ready, - port_probe_ctx); + port_probe_context_step (port_probe_ctx); } static void @@ -635,9 +437,7 @@ device_port_released_cb (MMDevice *device, GUdevDevice *port, FindDeviceSupportContext *ctx) { - mm_dbg ("Aborting port support check for (%s/%s)", - g_udev_device_get_subsystem (port), - g_udev_device_get_name (port)); + /* TODO: abort probing on that port */ } static gboolean @@ -879,11 +679,11 @@ mm_plugin_manager_init (MMPluginManager *manager) MM_TYPE_PLUGIN_MANAGER, MMPluginManagerPrivate); - manager->priv->supports = g_hash_table_new_full ( - g_str_hash, - g_str_equal, - g_free, - (GDestroyNotify)supports_info_list_free); + /* manager->priv->supports = g_hash_table_new_full ( */ + /* g_str_hash, */ + /* g_str_equal, */ + /* g_free, */ + /* (GDestroyNotify)supports_info_list_free); */ } static gboolean @@ -900,12 +700,12 @@ finalize (GObject *object) { MMPluginManager *self = MM_PLUGIN_MANAGER (object); - /* The Plugin Manager will only be finalized when all support tasks have - * been finished (as the GSimpleAsyncResult takes a reference to the object. - * Therefore, the hash table of support tasks should always be empty. - */ - g_assert (g_hash_table_size (self->priv->supports) == 0); - g_hash_table_destroy (self->priv->supports); + /* /\* The Plugin Manager will only be finalized when all support tasks have */ + /* * been finished (as the GSimpleAsyncResult takes a reference to the object. */ + /* * Therefore, the hash table of support tasks should always be empty. */ + /* *\/ */ + /* g_assert (g_hash_table_size (self->priv->supports) == 0); */ + /* g_hash_table_destroy (self->priv->supports); */ /* Cleanup list of plugins */ g_slist_foreach (self->priv->plugins, (GFunc)g_object_unref, NULL); |