aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-plugin-manager.c742
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);