aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-07-10 10:24:58 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-08-06 20:06:45 +0200
commitaaa487094e140583c4e652c8f59e38431d77b865 (patch)
tree2b756577c7ebbf6b0fd1ef72d8fad5aa3a3c15c7 /src
parenta1ffbdf1c8fef089e8c114649ed2161bab2aaaa6 (diff)
plugin-manager: simplify device/port probing logic
The plugin manager no longer needs to take care of keeping track of which probes are being run and to which physical device they correspond, as the upper layer's `MMDevice' already does this. This simplifies the internal logic quite a lot, as we can now easily suggest plugins to the remaining port probes of the same device directly.
Diffstat (limited to 'src')
-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);