aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-10-26 13:41:27 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-10-30 15:35:58 +0100
commit0ca6ae1b4b142dfa947bec45c833388f86cc9709 (patch)
treebabbea5b0360bb252154903ee9487589d2a5e789
parente5b4b4d0e5ab11a581504ce88be2a1aa317524e8 (diff)
plugin-manager,plugin: run pre-probing filters early
For each port, we will construct the list of plugins to test with. In that list we will include those plugins which are likely to handle a given port, so we will skip all those which aren't. To see if a plugin is likely or not, we will run the pre-probing filters before adding them to the list, with the new `mm_plugin_discard_port_early()'. This method will return one of these hints: * UNSUPPORTED: The plugin will not be able to handle this port. * MAYBE: The plugin may handle this port. * LIKELY: The plugin may (very likely) handle this port. * SUPPORTED: If any plugin should support the port, this is it. Plugins reported to be 'likely' supporting the port will be probed before the ones reported just as 'maybe'. If a plugin reports 'supported' only that one and the fallback generic ones will be tried.
-rw-r--r--src/mm-plugin-manager.c119
-rw-r--r--src/mm-plugin.c82
-rw-r--r--src/mm-plugin.h15
3 files changed, 152 insertions, 64 deletions
diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c
index d5759b65..56290e19 100644
--- a/src/mm-plugin-manager.c
+++ b/src/mm-plugin-manager.c
@@ -42,9 +42,12 @@ G_DEFINE_TYPE_EXTENDED (MMPluginManager, mm_plugin_manager, G_TYPE_OBJECT, 0,
initable_iface_init));
struct _MMPluginManagerPrivate {
- /* The list of plugins. It is loaded once when the program starts, and the
- * list is NOT expected to change after that. */
+ /* This list contains all plugins except for the generic one, order is not
+ * important. It is loaded once when the program starts, and the list is NOT
+ * expected to change after that.*/
GList *plugins;
+ /* Last, the generic plugin. */
+ MMPlugin *generic;
};
/*****************************************************************************/
@@ -65,6 +68,7 @@ typedef struct {
FindDeviceSupportContext *parent_ctx;
GUdevDevice *port;
+ GList *plugins;
GList *current;
MMPlugin *best_plugin;
MMPlugin *suggested_plugin;
@@ -86,6 +90,8 @@ port_probe_context_free (PortProbeContext *ctx)
g_object_unref (ctx->best_plugin);
if (ctx->suggested_plugin)
g_object_unref (ctx->suggested_plugin);
+ if (ctx->plugins)
+ g_list_free_full (ctx->plugins, (GDestroyNotify)g_object_unref);
g_object_unref (ctx->port);
g_slice_free (PortProbeContext, ctx);
}
@@ -426,6 +432,62 @@ port_probe_context_step (PortProbeContext *port_probe_ctx)
port_probe_ctx);
}
+static GList *
+build_plugins_list (MMPluginManager *self,
+ MMDevice *device,
+ GUdevDevice *port)
+{
+ GList *list = NULL;
+ GList *l;
+ gboolean supported_found = FALSE;
+
+ for (l = self->priv->plugins; l && !supported_found; l = g_list_next (l)) {
+ MMPluginSupportsHint hint;
+
+ hint = mm_plugin_discard_port_early (MM_PLUGIN (l->data), device, port);
+ switch (hint) {
+ case MM_PLUGIN_SUPPORTS_HINT_UNSUPPORTED:
+ /* Fully discard */
+ break;
+ case MM_PLUGIN_SUPPORTS_HINT_MAYBE:
+ /* Maybe supported, add to tail of list */
+ list = g_list_append (list, g_object_ref (l->data));
+ break;
+ case MM_PLUGIN_SUPPORTS_HINT_LIKELY:
+ /* Likely supported, add to head of list */
+ list = g_list_prepend (list, g_object_ref (l->data));
+ break;
+ case MM_PLUGIN_SUPPORTS_HINT_SUPPORTED:
+ /* Really supported, clean existing list and add it alone */
+ if (list) {
+ g_list_free_full (list, (GDestroyNotify)g_object_unref);
+ list = NULL;
+ }
+ list = g_list_prepend (list, g_object_ref (l->data));
+ /* This will end the loop as well */
+ supported_found = TRUE;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+
+ /* Add the generic plugin at the end of the list */
+ if (self->priv->generic)
+ list = g_list_append (list, g_object_ref (self->priv->generic));
+
+ mm_info ("(Plugin Manager) [%s] Found '%u' plugins to try...",
+ g_udev_device_get_name (port),
+ g_list_length (list));
+ for (l = list; l; l = g_list_next (l)) {
+ mm_info ("(Plugin Manager) [%s] Will try with plugin '%s'",
+ g_udev_device_get_name (port),
+ mm_plugin_get_name (MM_PLUGIN (l->data)));
+ }
+
+ return list;
+}
+
static void
device_port_grabbed_cb (MMDevice *device,
GUdevDevice *port,
@@ -433,17 +495,15 @@ device_port_grabbed_cb (MMDevice *device,
{
PortProbeContext *port_probe_ctx;
- mm_dbg ("(%s/%s) Launching port support check",
- g_udev_device_get_subsystem (port),
- g_udev_device_get_name (port));
/* Launch probing task on this port with the first plugin of the list */
port_probe_ctx = g_slice_new0 (PortProbeContext);
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;
+ /* Setup plugins to probe and first one to check */
+ port_probe_ctx->plugins = build_plugins_list (ctx->self, device, port);
+ port_probe_ctx->current = port_probe_ctx->plugins;
/* If we got one suggested, it will be the first one */
port_probe_ctx->suggested_plugin = (!!mm_device_peek_plugin (device) ?
@@ -585,9 +645,7 @@ load_plugins (MMPluginManager *self,
{
GDir *dir = NULL;
const gchar *fname;
- MMPlugin *generic_plugin = NULL;
gchar *plugindir_display = NULL;
- GList *l;
if (!g_module_supported ()) {
g_set_error (error,
@@ -622,27 +680,25 @@ load_plugins (MMPluginManager *self,
plugin = load_plugin (path);
g_free (path);
- if (plugin) {
- if (g_str_equal (mm_plugin_get_name (plugin),
- MM_PLUGIN_GENERIC_NAME))
- generic_plugin = plugin;
- else
- self->priv->plugins = g_list_append (self->priv->plugins,
- plugin);
- }
- }
+ if (!plugin)
+ continue;
+
+ mm_info ("Loaded plugin '%s'", mm_plugin_get_name (plugin));
- /* Sort last plugins that request it */
- self->priv->plugins = g_list_sort (self->priv->plugins,
- (GCompareFunc)mm_plugin_cmp);
+ if (g_str_equal (mm_plugin_get_name (plugin), MM_PLUGIN_GENERIC_NAME))
+ /* Generic plugin */
+ self->priv->generic = plugin;
+ else
+ /* Vendor specific plugin */
+ self->priv->plugins = g_list_append (self->priv->plugins, plugin);
+ }
- /* Make sure the generic plugin is last */
- if (generic_plugin)
- self->priv->plugins = g_list_append (self->priv->plugins,
- generic_plugin);
+ /* Check the generic plugin once all looped */
+ if (!self->priv->generic)
+ mm_warn ("Generic plugin not loaded");
/* Treat as error if we don't find any plugin */
- if (!self->priv->plugins) {
+ if (!self->priv->plugins && !self->priv->generic) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_NO_PLUGINS,
@@ -651,20 +707,16 @@ load_plugins (MMPluginManager *self,
goto out;
}
- /* Now report about all the found plugins, in the same order they will be
- * used while checking support */
- for (l = self->priv->plugins; l; l = g_list_next (l))
- mm_info ("Loaded plugin '%s'", mm_plugin_get_name (MM_PLUGIN (l->data)));
-
mm_info ("Successfully loaded %u plugins",
- g_list_length (self->priv->plugins));
+ g_list_length (self->priv->plugins) + !!self->priv->generic);
out:
if (dir)
g_dir_close (dir);
g_free (plugindir_display);
- return !!self->priv->plugins;
+ /* Return TRUE if at least one plugin found */
+ return (self->priv->plugins || self->priv->generic);
}
MMPluginManager *
@@ -704,6 +756,7 @@ dispose (GObject *object)
g_list_free_full (self->priv->plugins, (GDestroyNotify)g_object_unref);
self->priv->plugins = NULL;
}
+ g_clear_object (&self->priv->generic);
G_OBJECT_CLASS (mm_plugin_manager_parent_class)->dispose (object);
}
diff --git a/src/mm-plugin.c b/src/mm-plugin.c
index fff6f0a8..5069f0ee 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -43,31 +43,48 @@ G_DEFINE_TYPE (MMPlugin, mm_plugin, G_TYPE_OBJECT)
/* Virtual port corresponding to the embeded modem */
static gchar *virtual_port[] = {"smd0", NULL};
+#define HAS_POST_PROBING_FILTERS(self) \
+ (self->priv->vendor_strings || \
+ self->priv->product_strings || \
+ self->priv->forbidden_product_strings || \
+ self->priv->allowed_icera || \
+ self->priv->forbidden_icera || \
+ self->priv->custom_init)
+
+
struct _MMPluginPrivate {
gchar *name;
GHashTable *tasks;
- /* Plugin-specific setups */
+ /* Pre-probing filters */
gchar **subsystems;
gchar **drivers;
gchar **forbidden_drivers;
guint16 *vendor_ids;
mm_uint16_pair *product_ids;
mm_uint16_pair *forbidden_product_ids;
+ gchar **udev_tags;
+
+ /* Post probing filters */
gchar **vendor_strings;
mm_str_pair *product_strings;
mm_str_pair *forbidden_product_strings;
- gchar **udev_tags;
+ gboolean allowed_icera;
+ gboolean forbidden_icera;
+
+ /* Probing setup */
gboolean at;
gboolean single_at;
gboolean qcdm;
gboolean icera_probe;
- gboolean allowed_icera;
- gboolean forbidden_icera;
MMPortProbeAtCommand *custom_at_probe;
- MMAsyncMethod *custom_init;
guint64 send_delay;
gboolean remove_echo;
+
+ /* Probing setup and/or post-probing filter.
+ * Plugins may use this method to decide whether they support a given
+ * port or not, so should also be considered kind of post-probing filter. */
+ MMAsyncMethod *custom_init;
};
enum {
@@ -106,30 +123,6 @@ mm_plugin_get_name (MMPlugin *self)
/*****************************************************************************/
-gint
-mm_plugin_cmp (const MMPlugin *plugin_a,
- const MMPlugin *plugin_b)
-{
- /* If we have any post-probing filter, we need to sort the plugin last */
-#define SORT_LAST(self) (self->priv->vendor_strings || \
- self->priv->product_strings || \
- self->priv->forbidden_product_strings)
-
- /* The order of the plugins in the list is the same order used to check
- * whether the plugin can manage a given modem:
- * - First, modems that will check vendor ID from udev.
- * - Then, modems that report to be sorted last (those which will check
- * vendor ID also from the probed ones..
- */
- if (SORT_LAST (plugin_a) && !SORT_LAST (plugin_b))
- return 1;
- if (!SORT_LAST (plugin_a) && SORT_LAST (plugin_b))
- return -1;
- return 0;
-}
-
-/*****************************************************************************/
-
static gboolean
device_file_exists (const char *name)
{
@@ -747,6 +740,37 @@ out:
/*****************************************************************************/
+MMPluginSupportsHint
+mm_plugin_discard_port_early (MMPlugin *self,
+ MMDevice *device,
+ GUdevDevice *port)
+{
+ gboolean need_vendor_probing = FALSE;
+ gboolean need_product_probing = FALSE;
+
+ /* If fully filtered by pre-probing filters, port unsupported */
+ if (apply_pre_probing_filters (self,
+ device,
+ port,
+ &need_vendor_probing,
+ &need_product_probing))
+ return MM_PLUGIN_SUPPORTS_HINT_UNSUPPORTED;
+
+ /* If there are no post-probing filters, this plugin is the only one (except
+ * for the generic one) which will grab the port */
+ if (!HAS_POST_PROBING_FILTERS (self))
+ return MM_PLUGIN_SUPPORTS_HINT_SUPPORTED;
+
+ /* If no vendor/product probing needed, plugin is likely supported */
+ if (!need_vendor_probing && !need_product_probing)
+ return MM_PLUGIN_SUPPORTS_HINT_LIKELY;
+
+ /* If vendor/product probing is needed, plugin may be supported */
+ return MM_PLUGIN_SUPPORTS_HINT_MAYBE;
+}
+
+/*****************************************************************************/
+
MMBaseModem *
mm_plugin_create_modem (MMPlugin *self,
MMDevice *device,
diff --git a/src/mm-plugin.h b/src/mm-plugin.h
index 6d5d14e1..a423ceb0 100644
--- a/src/mm-plugin.h
+++ b/src/mm-plugin.h
@@ -67,6 +67,13 @@ typedef enum {
MM_PLUGIN_SUPPORTS_PORT_SUPPORTED
} MMPluginSupportsResult;
+typedef enum {
+ MM_PLUGIN_SUPPORTS_HINT_UNSUPPORTED,
+ MM_PLUGIN_SUPPORTS_HINT_MAYBE,
+ MM_PLUGIN_SUPPORTS_HINT_LIKELY,
+ MM_PLUGIN_SUPPORTS_HINT_SUPPORTED,
+} MMPluginSupportsHint;
+
typedef struct _MMPlugin MMPlugin;
typedef struct _MMPluginClass MMPluginClass;
typedef struct _MMPluginPrivate MMPluginPrivate;
@@ -102,8 +109,12 @@ struct _MMPluginClass {
GType mm_plugin_get_type (void);
const gchar *mm_plugin_get_name (MMPlugin *plugin);
-gint mm_plugin_cmp (const MMPlugin *plugin_a,
- const MMPlugin *plugin_b);
+
+/* This method will run all pre-probing filters, to see if we can discard this
+ * plugin from the probing logic as soon as possible. */
+MMPluginSupportsHint mm_plugin_discard_port_early (MMPlugin *plugin,
+ MMDevice *device,
+ GUdevDevice *port);
void mm_plugin_supports_port (MMPlugin *plugin,
MMDevice *device,