manager: integrate the Plugin Manager
All plugin handling and port support checks now done by the Plugin Manager.
This commit is contained in:
committed by
Aleksander Morgado
parent
fad89b1d7e
commit
916cf5dd3e
+204
-558
@@ -11,7 +11,8 @@
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2010 Red Hat, Inc.
|
||||
* Copyright (C) 2009 - 2011 Red Hat, Inc.
|
||||
* Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
#include "mm-manager.h"
|
||||
#include "mm-plugin-manager.h"
|
||||
#include "mm-auth-provider.h"
|
||||
#include "mm-errors.h"
|
||||
#include "mm-plugin.h"
|
||||
@@ -38,6 +40,11 @@ static gboolean impl_manager_set_logging (MMManager *manager,
|
||||
const char *level,
|
||||
GError **error);
|
||||
|
||||
static void grab_port (MMManager *manager,
|
||||
MMPlugin *plugin,
|
||||
GUdevDevice *device,
|
||||
GUdevDevice *physical_device);
|
||||
|
||||
#include "mm-manager-glue.h"
|
||||
|
||||
G_DEFINE_TYPE (MMManager, mm_manager, G_TYPE_OBJECT)
|
||||
@@ -56,160 +63,41 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||
typedef struct {
|
||||
DBusGConnection *connection;
|
||||
GUdevClient *udev;
|
||||
GSList *plugins;
|
||||
GHashTable *modems;
|
||||
|
||||
MMAuthProvider *authp;
|
||||
|
||||
GHashTable *supports;
|
||||
/* The Plugin Manager object */
|
||||
MMPluginManager *plugin_manager;
|
||||
} MMManagerPrivate;
|
||||
|
||||
typedef struct {
|
||||
MMManager *manager;
|
||||
char *subsys;
|
||||
char *name;
|
||||
char *physdev_path;
|
||||
GSList *plugins;
|
||||
GSList *cur_plugin;
|
||||
guint defer_id;
|
||||
guint done_id;
|
||||
GUdevDevice *device;
|
||||
GUdevDevice *physical_device;
|
||||
} FindPortSupportContext;
|
||||
|
||||
guint32 best_level;
|
||||
MMPlugin *best_plugin;
|
||||
} SupportsInfo;
|
||||
|
||||
|
||||
static MMPlugin *
|
||||
load_plugin (const char *path)
|
||||
static FindPortSupportContext *
|
||||
find_port_support_context_new (MMManager *manager,
|
||||
GUdevDevice *device,
|
||||
GUdevDevice *physical_device)
|
||||
{
|
||||
MMPlugin *plugin = NULL;
|
||||
GModule *module;
|
||||
MMPluginCreateFunc plugin_create_func;
|
||||
int *major_plugin_version, *minor_plugin_version;
|
||||
FindPortSupportContext *ctx;
|
||||
|
||||
module = g_module_open (path, G_MODULE_BIND_LAZY);
|
||||
if (!module) {
|
||||
g_warning ("Could not load plugin %s: %s", path, g_module_error ());
|
||||
return NULL;
|
||||
}
|
||||
ctx = g_new0 (FindPortSupportContext, 1);
|
||||
ctx->manager = manager;
|
||||
ctx->device = g_object_ref (device);
|
||||
ctx->physical_device = g_object_ref (physical_device);
|
||||
|
||||
if (!g_module_symbol (module, "mm_plugin_major_version", (gpointer *) &major_plugin_version)) {
|
||||
g_warning ("Could not load plugin %s: Missing major version info", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*major_plugin_version != MM_PLUGIN_MAJOR_VERSION) {
|
||||
g_warning ("Could not load plugin %s: Plugin major version %d, %d is required",
|
||||
path, *major_plugin_version, MM_PLUGIN_MAJOR_VERSION);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (module, "mm_plugin_minor_version", (gpointer *) &minor_plugin_version)) {
|
||||
g_warning ("Could not load plugin %s: Missing minor version info", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*minor_plugin_version != MM_PLUGIN_MINOR_VERSION) {
|
||||
g_warning ("Could not load plugin %s: Plugin minor version %d, %d is required",
|
||||
path, *minor_plugin_version, MM_PLUGIN_MINOR_VERSION);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (module, "mm_plugin_create", (gpointer *) &plugin_create_func)) {
|
||||
g_warning ("Could not load plugin %s: %s", path, g_module_error ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
plugin = (*plugin_create_func) ();
|
||||
if (plugin) {
|
||||
g_object_weak_ref (G_OBJECT (plugin), (GWeakNotify) g_module_close, module);
|
||||
} else
|
||||
mm_warn ("Could not load plugin %s: initialization failed", path);
|
||||
|
||||
out:
|
||||
if (!plugin)
|
||||
g_module_close (module);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_plugins (const MMPlugin *plugin_a,
|
||||
const MMPlugin *plugin_b)
|
||||
{
|
||||
/* 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 (mm_plugin_get_sort_last (plugin_a) &&
|
||||
!mm_plugin_get_sort_last (plugin_b))
|
||||
return 1;
|
||||
if (!mm_plugin_get_sort_last (plugin_a) &&
|
||||
mm_plugin_get_sort_last (plugin_b))
|
||||
return -1;
|
||||
return 0;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void
|
||||
found_plugin (MMPlugin *plugin)
|
||||
find_port_support_context_free (FindPortSupportContext *ctx)
|
||||
{
|
||||
mm_info ("Loaded plugin '%s'", mm_plugin_get_name (plugin));
|
||||
}
|
||||
|
||||
static void
|
||||
load_plugins (MMManager *manager)
|
||||
{
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
|
||||
GDir *dir;
|
||||
const char *fname;
|
||||
MMPlugin *generic_plugin = NULL;
|
||||
|
||||
if (!g_module_supported ()) {
|
||||
g_warning ("GModules are not supported on your platform!");
|
||||
return;
|
||||
}
|
||||
|
||||
dir = g_dir_open (PLUGINDIR, 0, NULL);
|
||||
if (!dir) {
|
||||
g_warning ("No plugins found");
|
||||
return;
|
||||
}
|
||||
|
||||
while ((fname = g_dir_read_name (dir)) != NULL) {
|
||||
char *path;
|
||||
MMPlugin *plugin;
|
||||
|
||||
if (!g_str_has_suffix (fname, G_MODULE_SUFFIX))
|
||||
continue;
|
||||
|
||||
path = g_module_build_path (PLUGINDIR, fname);
|
||||
plugin = load_plugin (path);
|
||||
g_free (path);
|
||||
|
||||
if (plugin) {
|
||||
if (!strcmp (mm_plugin_get_name (plugin), MM_PLUGIN_GENERIC_NAME))
|
||||
generic_plugin = plugin;
|
||||
else
|
||||
priv->plugins = g_slist_append (priv->plugins, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort last plugins that request it */
|
||||
priv->plugins = g_slist_sort (priv->plugins, (GCompareFunc)compare_plugins);
|
||||
|
||||
/* Make sure the generic plugin is last */
|
||||
if (generic_plugin)
|
||||
priv->plugins = g_slist_append (priv->plugins, generic_plugin);
|
||||
|
||||
/* Now report about all the found plugins, in the same order they will be
|
||||
* used while checking support */
|
||||
g_slist_foreach (priv->plugins, (GFunc)found_plugin, NULL);
|
||||
|
||||
mm_info ("Successfully loaded %u plugins", g_slist_length (priv->plugins));
|
||||
|
||||
g_dir_close (dir);
|
||||
g_object_unref (ctx->device);
|
||||
g_object_unref (ctx->physical_device);
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
MMManager *
|
||||
@@ -221,12 +109,23 @@ mm_manager_new (DBusGConnection *bus)
|
||||
|
||||
manager = (MMManager *) g_object_new (MM_TYPE_MANAGER, NULL);
|
||||
if (manager) {
|
||||
GError *error = NULL;
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
|
||||
|
||||
priv->connection = dbus_g_connection_ref (bus);
|
||||
dbus_g_connection_register_g_object (priv->connection,
|
||||
MM_DBUS_PATH,
|
||||
G_OBJECT (manager));
|
||||
|
||||
priv->plugin_manager = mm_plugin_manager_new (&error);
|
||||
if (!priv->plugin_manager) {
|
||||
mm_warn ("Error creating Plugin Manager: '%s'",
|
||||
error ? error->message : "unknown error");
|
||||
g_clear_error (&error);
|
||||
|
||||
g_object_unref (manager);
|
||||
manager = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return manager;
|
||||
@@ -247,36 +146,13 @@ remove_modem (MMManager *manager, MMModem *modem)
|
||||
g_free (device);
|
||||
}
|
||||
|
||||
/* Return the first outstanding supports task */
|
||||
static SupportsInfo *
|
||||
find_supports_info (MMManager *self, MMModem *modem)
|
||||
{
|
||||
char *modem_physdev;
|
||||
GHashTableIter iter;
|
||||
SupportsInfo *info, *ret = NULL;
|
||||
|
||||
modem_physdev = mm_modem_get_device (modem);
|
||||
g_assert (modem_physdev);
|
||||
|
||||
/* Check for ports that are in the process of being interrogated by plugins */
|
||||
g_hash_table_iter_init (&iter, MM_MANAGER_GET_PRIVATE (self)->supports);
|
||||
while (!ret && g_hash_table_iter_next (&iter, NULL, (gpointer) &info)) {
|
||||
if (g_strcmp0 (info->physdev_path, modem_physdev) == 0)
|
||||
ret = info;
|
||||
}
|
||||
g_free (modem_physdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
check_export_modem (MMManager *self, MMModem *modem)
|
||||
{
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self);
|
||||
SupportsInfo *info;
|
||||
static guint32 id = 0, vid = 0, pid = 0;
|
||||
char *path, *data_device = NULL, *modem_physdev;
|
||||
GUdevDevice *physdev;
|
||||
const char *subsys = NULL;
|
||||
char *modem_physdev;
|
||||
const gchar *name;
|
||||
const gchar *subsys;
|
||||
|
||||
/* A modem is only exported to D-Bus when both of the following are true:
|
||||
*
|
||||
@@ -291,47 +167,62 @@ check_export_modem (MMManager *self, MMModem *modem)
|
||||
* chance that a port could show up after the modem is already created and
|
||||
* all other ports are already handled. That chance is very small though.
|
||||
*/
|
||||
|
||||
info = find_supports_info (self, modem);
|
||||
if (info) {
|
||||
mm_dbg ("(%s/%s): outstanding support task prevents export of %s",
|
||||
info->subsys, info->name, info->physdev_path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Obviously don't re-export a modem, or try to export one that's not valid */
|
||||
if ( g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG)
|
||||
|| !mm_modem_get_valid (modem))
|
||||
return;
|
||||
|
||||
path = g_strdup_printf (MM_DBUS_PATH "/Modems/%d", id++);
|
||||
dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem));
|
||||
g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free);
|
||||
|
||||
modem_physdev = mm_modem_get_device (modem);
|
||||
g_assert (modem_physdev);
|
||||
mm_dbg ("Exported modem %s as %s", modem_physdev, path);
|
||||
|
||||
physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev);
|
||||
/* Check for ports that are in the process of being interrogated by plugins */
|
||||
if (mm_plugin_manager_is_finding_device_support (priv->plugin_manager,
|
||||
modem_physdev,
|
||||
&subsys,
|
||||
&name)) {
|
||||
mm_dbg ("(%s/%s): outstanding support task prevents export of %s",
|
||||
subsys, name, modem_physdev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Already exported? This can happen if the modem is exported and the kernel
|
||||
* discovers another of the modem's ports.
|
||||
*/
|
||||
if (g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG))
|
||||
goto out;
|
||||
|
||||
/* No outstanding port tasks, so if the modem is valid we can export it */
|
||||
if (mm_modem_get_valid (modem)) {
|
||||
static guint32 id = 0, vid = 0, pid = 0;
|
||||
char *path, *data_device = NULL;
|
||||
GUdevDevice *physdev;
|
||||
|
||||
subsys = NULL;
|
||||
|
||||
path = g_strdup_printf (MM_DBUS_PATH"/Modems/%d", id++);
|
||||
dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem));
|
||||
g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free);
|
||||
|
||||
mm_dbg ("Exported modem %s as %s", modem_physdev, path);
|
||||
|
||||
physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev);
|
||||
if (physdev)
|
||||
subsys = g_udev_device_get_subsystem (physdev);
|
||||
|
||||
g_object_get (G_OBJECT (modem),
|
||||
MM_MODEM_DATA_DEVICE, &data_device,
|
||||
MM_MODEM_HW_VID, &vid,
|
||||
MM_MODEM_HW_PID, &pid,
|
||||
NULL);
|
||||
mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)",
|
||||
path, (vid & 0xFFFF), (pid & 0xFFFF),
|
||||
subsys ? subsys : "unknown");
|
||||
mm_dbg ("(%s): data port is %s", path, data_device);
|
||||
g_free (data_device);
|
||||
|
||||
if (physdev)
|
||||
g_object_unref (physdev);
|
||||
|
||||
g_signal_emit (self, signals[DEVICE_ADDED], 0, modem);
|
||||
}
|
||||
|
||||
out:
|
||||
g_free (modem_physdev);
|
||||
if (physdev)
|
||||
subsys = g_udev_device_get_subsystem (physdev);
|
||||
|
||||
g_object_get (G_OBJECT (modem),
|
||||
MM_MODEM_DATA_DEVICE, &data_device,
|
||||
MM_MODEM_HW_VID, &vid,
|
||||
MM_MODEM_HW_PID, &pid,
|
||||
NULL);
|
||||
mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)",
|
||||
path, (vid & 0xFFFF), (pid & 0xFFFF),
|
||||
subsys ? subsys : "unknown");
|
||||
mm_dbg ("(%s): data port is %s", path, data_device);
|
||||
g_free (data_device);
|
||||
|
||||
if (physdev)
|
||||
g_object_unref (physdev);
|
||||
|
||||
g_signal_emit (self, signals[DEVICE_ADDED], 0, modem);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -416,7 +307,6 @@ find_modem_for_device (MMManager *manager, const char *device)
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static MMModem *
|
||||
find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
|
||||
{
|
||||
@@ -434,330 +324,107 @@ find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SupportsInfo *
|
||||
supports_info_new (MMManager *self,
|
||||
const char *subsys,
|
||||
const char *name,
|
||||
const char *physdev_path)
|
||||
{
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self);
|
||||
SupportsInfo *info;
|
||||
|
||||
info = g_malloc0 (sizeof (SupportsInfo));
|
||||
info->manager = self;
|
||||
info->subsys = g_strdup (subsys);
|
||||
info->name = g_strdup (name);
|
||||
info->physdev_path = g_strdup (physdev_path);
|
||||
info->plugins = g_slist_copy (priv->plugins);
|
||||
info->cur_plugin = info->plugins;
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
supports_info_free (SupportsInfo *info)
|
||||
find_port_support_ready_cb (MMPluginManager *plugin_manager,
|
||||
GAsyncResult *result,
|
||||
FindPortSupportContext *ctx)
|
||||
{
|
||||
/* Cancel any in-process operation on the first plugin */
|
||||
if (info->cur_plugin)
|
||||
mm_plugin_supports_port_cancel (MM_PLUGIN (info->cur_plugin->data),
|
||||
info->subsys,
|
||||
info->name);
|
||||
|
||||
if (info->defer_id)
|
||||
g_source_remove (info->defer_id);
|
||||
|
||||
if (info->done_id)
|
||||
g_source_remove (info->done_id);
|
||||
|
||||
g_free (info->subsys);
|
||||
g_free (info->name);
|
||||
g_slist_free (info->plugins);
|
||||
memset (info, 0, sizeof (SupportsInfo));
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_key (const char *subsys, const char *name)
|
||||
{
|
||||
return g_strdup_printf ("%s%s", subsys, name);
|
||||
}
|
||||
|
||||
|
||||
static void supports_callback (MMPlugin *plugin,
|
||||
const char *subsys,
|
||||
const char *name,
|
||||
guint32 level,
|
||||
gpointer user_data);
|
||||
|
||||
static void supports_port_ready_cb (MMPlugin *plugin,
|
||||
GAsyncResult *result,
|
||||
SupportsInfo *info);
|
||||
|
||||
static gboolean
|
||||
supports_defer_timeout (gpointer user_data)
|
||||
{
|
||||
SupportsInfo *info = user_data;
|
||||
MMModem *existing;
|
||||
|
||||
existing = find_modem_for_device (info->manager, info->physdev_path);
|
||||
|
||||
mm_dbg ("(%s): re-checking support...", info->name);
|
||||
mm_plugin_supports_port (MM_PLUGIN (info->cur_plugin->data),
|
||||
info->subsys,
|
||||
info->name,
|
||||
info->physdev_path,
|
||||
existing,
|
||||
(GAsyncReadyCallback)supports_port_ready_cb,
|
||||
info);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
supports_port_ready_cb (MMPlugin *plugin,
|
||||
GAsyncResult *result,
|
||||
SupportsInfo *info)
|
||||
{
|
||||
MMPluginSupportsResult supports_result;
|
||||
GError *error = NULL;
|
||||
guint level = 0;
|
||||
MMPlugin *best_plugin;
|
||||
|
||||
/* Get supports check results */
|
||||
supports_result = mm_plugin_supports_port_finish (plugin,
|
||||
result,
|
||||
&level,
|
||||
&error);
|
||||
if (error) {
|
||||
mm_warn ("(%s): (%s) error when checking support: '%s'",
|
||||
mm_plugin_get_name (plugin),
|
||||
info->name,
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
switch (supports_result) {
|
||||
case MM_PLUGIN_SUPPORTS_PORT_SUPPORTED:
|
||||
/* Report support level to the callback */
|
||||
supports_callback (plugin, info->subsys, info->name, level, info);
|
||||
break;
|
||||
case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED:
|
||||
/* If the plugin knows it doesn't support the modem, just call the
|
||||
* callback and indicate 0 support.
|
||||
*/
|
||||
supports_callback (plugin, info->subsys, info->name, 0, info);
|
||||
break;
|
||||
case MM_PLUGIN_SUPPORTS_PORT_DEFER:
|
||||
mm_dbg ("(%s): (%s) deferring support check",
|
||||
mm_plugin_get_name (plugin),
|
||||
info->name);
|
||||
if (info->defer_id)
|
||||
g_source_remove (info->defer_id);
|
||||
|
||||
/* defer port detection for a bit as requested by the plugin */
|
||||
info->defer_id = g_timeout_add (3000, supports_defer_timeout, info);
|
||||
break;
|
||||
case MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS:
|
||||
/* This should never happen at this level */
|
||||
g_warn_if_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
supports_cleanup (MMManager *self,
|
||||
const char *subsys,
|
||||
const char *name,
|
||||
MMModem *modem)
|
||||
{
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self);
|
||||
char *key;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (subsys != NULL);
|
||||
g_return_if_fail (name != NULL);
|
||||
|
||||
key = get_key (subsys, name);
|
||||
g_hash_table_remove (priv->supports, key);
|
||||
g_free (key);
|
||||
|
||||
if (modem == NULL)
|
||||
return;
|
||||
|
||||
if ( (find_supports_info (self, modem) == NULL)
|
||||
&& !g_object_get_data (G_OBJECT (modem), "organized")) {
|
||||
/* Yay, we're done with supports tasks, tell the modem to organize
|
||||
* all its ports. Guard against multiple organize calls though since
|
||||
* if the kernel or udev is slow, ports may show up long after the
|
||||
* first bunch of supports tasks is done.
|
||||
*/
|
||||
g_object_set_data (G_OBJECT (modem), "organized", GUINT_TO_POINTER (1));
|
||||
if (!mm_modem_organize_ports (modem, &error)) {
|
||||
mm_err ("Failed to organize modem ports: (%d) %s",
|
||||
error ? error->code : -1,
|
||||
error && error->message ? error->message : "(unknown)");
|
||||
g_clear_error (&error);
|
||||
remove_modem (self, modem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Each time a supports task is cleaned up, check whether the modem is
|
||||
* now completely probed/handled and should be exported to D-Bus clients.
|
||||
*
|
||||
* IMPORTANT: this must be done after removing the supports info from
|
||||
* priv->supports since check_export_modem() searches through priv->supports
|
||||
* for outstanding supports tasks.
|
||||
*/
|
||||
check_export_modem (self, modem);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_grab_port (gpointer user_data)
|
||||
{
|
||||
SupportsInfo *info = user_data;
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (info->manager);
|
||||
MMModem *modem = NULL;
|
||||
GError *error = NULL;
|
||||
GSList *iter;
|
||||
|
||||
/* No more plugins to try */
|
||||
if (info->best_plugin) {
|
||||
best_plugin = mm_plugin_manager_find_port_support_finish (plugin_manager,
|
||||
result,
|
||||
&error);
|
||||
if (!best_plugin) {
|
||||
MMModem *existing;
|
||||
|
||||
existing = g_hash_table_lookup (priv->modems, info->physdev_path);
|
||||
|
||||
/* Create the modem */
|
||||
modem = mm_plugin_grab_port (info->best_plugin, info->subsys, info->name, existing, &error);
|
||||
if (modem) {
|
||||
guint32 modem_type = MM_MODEM_TYPE_UNKNOWN;
|
||||
const char *type_name = "UNKNOWN";
|
||||
char *device;;
|
||||
|
||||
g_object_get (G_OBJECT (modem), MM_MODEM_TYPE, &modem_type, NULL);
|
||||
if (modem_type == MM_MODEM_TYPE_GSM)
|
||||
type_name = "GSM";
|
||||
else if (modem_type == MM_MODEM_TYPE_CDMA)
|
||||
type_name = "CDMA";
|
||||
|
||||
device = mm_modem_get_device (modem);
|
||||
mm_info ("(%s): %s modem %s claimed port %s",
|
||||
mm_plugin_get_name (info->best_plugin),
|
||||
type_name,
|
||||
device,
|
||||
info->name);
|
||||
g_free (device);
|
||||
|
||||
add_modem (info->manager, modem, info->best_plugin);
|
||||
if (error) {
|
||||
mm_dbg ("(%s/%s): error checking support: '%s'",
|
||||
g_udev_device_get_subsystem (ctx->device),
|
||||
g_udev_device_get_name (ctx->device),
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
mm_warn ("plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
|
||||
mm_plugin_get_name (info->best_plugin),
|
||||
info->subsys,
|
||||
info->name,
|
||||
error ? error->code : -1,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
modem = existing;
|
||||
mm_dbg ("(%s/%s): not supported by any plugin",
|
||||
g_udev_device_get_subsystem (ctx->device),
|
||||
g_udev_device_get_name (ctx->device));
|
||||
}
|
||||
|
||||
/* So we couldn't get a plugin for this port, we should anyway check if
|
||||
* there is already an existing modem for the physical device, and if
|
||||
* so, check if it can already be exported. */
|
||||
existing = find_modem_for_device (
|
||||
ctx->manager,
|
||||
g_udev_device_get_sysfs_path (ctx->physical_device));
|
||||
if (existing)
|
||||
check_export_modem (ctx->manager, existing);
|
||||
} else {
|
||||
mm_dbg ("(%s/%s): found plugin '%s' giving best support",
|
||||
g_udev_device_get_subsystem (ctx->device),
|
||||
g_udev_device_get_name (ctx->device),
|
||||
mm_plugin_get_name ((MMPlugin *)best_plugin));
|
||||
|
||||
grab_port (ctx->manager,
|
||||
best_plugin,
|
||||
ctx->device,
|
||||
ctx->physical_device);
|
||||
}
|
||||
|
||||
/* Tell each plugin to clean up any outstanding supports task */
|
||||
for (iter = info->plugins; iter; iter = g_slist_next (iter))
|
||||
mm_plugin_supports_port_cancel (MM_PLUGIN (iter->data),
|
||||
info->subsys,
|
||||
info->name);
|
||||
g_slist_free (info->plugins);
|
||||
info->cur_plugin = info->plugins = NULL;
|
||||
|
||||
supports_cleanup (info->manager, info->subsys, info->name, modem);
|
||||
return FALSE;
|
||||
find_port_support_context_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
supports_callback (MMPlugin *plugin,
|
||||
const char *subsys,
|
||||
const char *name,
|
||||
guint32 level,
|
||||
gpointer user_data)
|
||||
grab_port (MMManager *manager,
|
||||
MMPlugin *plugin,
|
||||
GUdevDevice *device,
|
||||
GUdevDevice *physical_device)
|
||||
{
|
||||
SupportsInfo *info = user_data;
|
||||
MMPlugin *next_plugin = NULL;
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
|
||||
MMModem *modem = NULL;
|
||||
GError *error = NULL;
|
||||
/* GSList *iter; */
|
||||
MMModem *existing;
|
||||
|
||||
/* Is this plugin's result better than any one we've tried before? */
|
||||
if (level > info->best_level) {
|
||||
info->best_level = level;
|
||||
info->best_plugin = plugin;
|
||||
}
|
||||
existing = g_hash_table_lookup (priv->modems,
|
||||
g_udev_device_get_sysfs_path (physical_device));
|
||||
|
||||
/* If there's already a modem for this port's physical device, stop asking
|
||||
* plugins because the same plugin that owns the modem gets this port no
|
||||
* matter what.
|
||||
*/
|
||||
existing = find_modem_for_device (info->manager, info->physdev_path);
|
||||
if (existing) {
|
||||
MMPlugin *existing_plugin;
|
||||
|
||||
existing_plugin = MM_PLUGIN (g_object_get_data (G_OBJECT (existing), MANAGER_PLUGIN_TAG));
|
||||
g_assert (existing_plugin);
|
||||
|
||||
if (plugin == existing_plugin) {
|
||||
if (level == 0) {
|
||||
/* 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);
|
||||
supports_cleanup (info->manager, info->subsys, info->name, existing);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, this port was supported by the plugin that owns the
|
||||
* port's physical modem, so we stop the supports checks anyway.
|
||||
*/
|
||||
next_plugin = NULL;
|
||||
} else if (info->best_plugin != existing_plugin) {
|
||||
/* If this port hasn't yet been handled by the right plugin, stop
|
||||
* asking all other plugins if they support this port, just let the
|
||||
* plugin that handles this port's physical device see if it
|
||||
* supports it.
|
||||
*/
|
||||
next_plugin = existing_plugin;
|
||||
} else {
|
||||
mm_dbg ("(%s/%s): plugin %p (%s) existing %p (%s) info->best %p (%s)",
|
||||
info->subsys, info->name,
|
||||
plugin,
|
||||
plugin ? mm_plugin_get_name (plugin) : "none",
|
||||
existing_plugin,
|
||||
existing_plugin ? mm_plugin_get_name (existing_plugin) : "none",
|
||||
info->best_plugin,
|
||||
info->best_plugin ? mm_plugin_get_name (info->best_plugin) : "none");
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
} else {
|
||||
info->cur_plugin = g_slist_next (info->cur_plugin);
|
||||
if (info->cur_plugin)
|
||||
next_plugin = MM_PLUGIN (info->cur_plugin->data);
|
||||
}
|
||||
|
||||
/* Don't bother with Generic if some other plugin already supports this port */
|
||||
if (next_plugin) {
|
||||
const char *next_name = mm_plugin_get_name (next_plugin);
|
||||
|
||||
if (info->best_plugin && !strcmp (next_name, MM_PLUGIN_GENERIC_NAME))
|
||||
next_plugin = NULL;
|
||||
}
|
||||
|
||||
if (next_plugin) {
|
||||
/* Try the next plugin */
|
||||
mm_plugin_supports_port (next_plugin,
|
||||
info->subsys,
|
||||
info->name,
|
||||
info->physdev_path,
|
||||
/* Create the modem */
|
||||
modem = mm_plugin_grab_port (plugin,
|
||||
g_udev_device_get_subsystem (device),
|
||||
g_udev_device_get_name (device),
|
||||
existing,
|
||||
(GAsyncReadyCallback)supports_port_ready_cb,
|
||||
info);
|
||||
&error);
|
||||
if (modem) {
|
||||
guint32 modem_type = MM_MODEM_TYPE_UNKNOWN;
|
||||
const gchar *type_name = "UNKNOWN";
|
||||
gchar *modem_device;
|
||||
|
||||
g_object_get (G_OBJECT (modem), MM_MODEM_TYPE, &modem_type, NULL);
|
||||
if (modem_type == MM_MODEM_TYPE_GSM)
|
||||
type_name = "GSM";
|
||||
else if (modem_type == MM_MODEM_TYPE_CDMA)
|
||||
type_name = "CDMA";
|
||||
|
||||
modem_device = mm_modem_get_device (modem);
|
||||
mm_info ("(%s): %s modem %s claimed port %s",
|
||||
mm_plugin_get_name (plugin),
|
||||
type_name,
|
||||
modem_device,
|
||||
g_udev_device_get_name (device));
|
||||
g_free (modem_device);
|
||||
|
||||
add_modem (manager, modem, plugin);
|
||||
} else {
|
||||
/* All done; let the best modem grab the port */
|
||||
info->done_id = g_idle_add (do_grab_port, info);
|
||||
mm_warn ("plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
|
||||
mm_plugin_get_name (plugin),
|
||||
g_udev_device_get_subsystem (device),
|
||||
g_udev_device_get_name (device),
|
||||
error ? error->code : -1,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
modem = existing;
|
||||
}
|
||||
|
||||
check_export_modem (manager, modem);
|
||||
}
|
||||
|
||||
static GUdevDevice *
|
||||
@@ -827,18 +494,13 @@ device_added (MMManager *manager, GUdevDevice *device)
|
||||
{
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
|
||||
const char *subsys, *name, *physdev_path, *physdev_subsys;
|
||||
SupportsInfo *info;
|
||||
char *key;
|
||||
gboolean found, is_candidate;
|
||||
gboolean is_candidate;
|
||||
GUdevDevice *physdev = NULL;
|
||||
MMPlugin *plugin;
|
||||
MMModem *existing;
|
||||
|
||||
g_return_if_fail (device != NULL);
|
||||
|
||||
if (!g_slist_length (priv->plugins))
|
||||
return;
|
||||
|
||||
subsys = g_udev_device_get_subsystem (device);
|
||||
name = g_udev_device_get_name (device);
|
||||
|
||||
@@ -860,11 +522,6 @@ device_added (MMManager *manager, GUdevDevice *device)
|
||||
if (find_modem_for_port (manager, subsys, name))
|
||||
return;
|
||||
|
||||
key = get_key (subsys, name);
|
||||
found = !!g_hash_table_lookup (priv->supports, key);
|
||||
if (found)
|
||||
goto out;
|
||||
|
||||
/* Find the port's physical device's sysfs path. This is the kernel device
|
||||
* that "owns" all the ports of the device, like the USB device or the PCI
|
||||
* device the provides each tty or network port.
|
||||
@@ -905,47 +562,51 @@ device_added (MMManager *manager, GUdevDevice *device)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Success; now ask plugins if they can handle this port */
|
||||
info = supports_info_new (manager, subsys, name, physdev_path);
|
||||
g_hash_table_insert (priv->supports, g_strdup (key), info);
|
||||
/* Already launched the same port support check? */
|
||||
if (mm_plugin_manager_is_finding_port_support (priv->plugin_manager,
|
||||
subsys,
|
||||
name,
|
||||
physdev_path)) {
|
||||
mm_dbg ("(%s/%s): support check already requested in port", subsys, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If this port's physical modem is already owned by a plugin, don't bother
|
||||
* asking all plugins whether they support this port, just let the owning
|
||||
* plugin check if it supports the port.
|
||||
*/
|
||||
plugin = MM_PLUGIN (info->cur_plugin->data);
|
||||
existing = find_modem_for_device (manager, physdev_path);
|
||||
if (existing)
|
||||
plugin = MM_PLUGIN (g_object_get_data (G_OBJECT (existing), MANAGER_PLUGIN_TAG));
|
||||
plugin = (existing ?
|
||||
MM_PLUGIN (g_object_get_data (G_OBJECT (existing), MANAGER_PLUGIN_TAG)) :
|
||||
NULL);
|
||||
|
||||
mm_plugin_supports_port (plugin,
|
||||
info->subsys,
|
||||
info->name,
|
||||
info->physdev_path,
|
||||
existing,
|
||||
(GAsyncReadyCallback)supports_port_ready_cb,
|
||||
info);
|
||||
/* Launch supports check in the Plugin Manager */
|
||||
mm_plugin_manager_find_port_support (
|
||||
priv->plugin_manager,
|
||||
subsys,
|
||||
name,
|
||||
physdev_path,
|
||||
plugin,
|
||||
existing,
|
||||
(GAsyncReadyCallback)find_port_support_ready_cb,
|
||||
find_port_support_context_new (manager,
|
||||
device,
|
||||
physdev));
|
||||
|
||||
out:
|
||||
if (physdev)
|
||||
g_object_unref (physdev);
|
||||
g_free (key);
|
||||
}
|
||||
|
||||
static void
|
||||
device_removed (MMManager *manager, GUdevDevice *device)
|
||||
{
|
||||
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
|
||||
MMModem *modem;
|
||||
const char *subsys, *name;
|
||||
char *key, *modem_device;
|
||||
SupportsInfo *info;
|
||||
gchar *modem_device;
|
||||
|
||||
g_return_if_fail (device != NULL);
|
||||
|
||||
if (!g_slist_length (priv->plugins))
|
||||
return;
|
||||
|
||||
subsys = g_udev_device_get_subsystem (device);
|
||||
name = g_udev_device_get_name (device);
|
||||
|
||||
@@ -978,19 +639,8 @@ device_removed (MMManager *manager, GUdevDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
/* Maybe a plugin is checking whether or not the port is supported */
|
||||
key = get_key (subsys, name);
|
||||
info = g_hash_table_lookup (priv->supports, key);
|
||||
|
||||
if (info) {
|
||||
if (info->plugins)
|
||||
mm_plugin_supports_port_cancel (MM_PLUGIN (info->plugins->data),
|
||||
subsys,
|
||||
name);
|
||||
g_hash_table_remove (priv->supports, key);
|
||||
}
|
||||
|
||||
g_free (key);
|
||||
/* Maybe a plugin is checking whether or not the port is supported.
|
||||
* TODO: Cancel every possible supports check in this port. */
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1180,9 +830,6 @@ mm_manager_init (MMManager *manager)
|
||||
priv->authp = mm_auth_provider_get ();
|
||||
|
||||
priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
load_plugins (manager);
|
||||
|
||||
priv->supports = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) supports_info_free);
|
||||
|
||||
priv->udev = g_udev_client_new (subsys);
|
||||
g_assert (priv->udev);
|
||||
@@ -1196,15 +843,14 @@ finalize (GObject *object)
|
||||
|
||||
mm_auth_provider_cancel_for_owner (priv->authp, object);
|
||||
|
||||
g_hash_table_destroy (priv->supports);
|
||||
g_hash_table_destroy (priv->modems);
|
||||
|
||||
g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL);
|
||||
g_slist_free (priv->plugins);
|
||||
|
||||
if (priv->udev)
|
||||
g_object_unref (priv->udev);
|
||||
|
||||
if (priv->plugin_manager)
|
||||
g_object_unref (priv->plugin_manager);
|
||||
|
||||
if (priv->connection)
|
||||
dbus_g_connection_unref (priv->connection);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user