diff options
Diffstat (limited to 'src/mm-manager.c')
-rw-r--r-- | src/mm-manager.c | 376 |
1 files changed, 165 insertions, 211 deletions
diff --git a/src/mm-manager.c b/src/mm-manager.c index a19c9446..beed08cc 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -2,12 +2,12 @@ #include <string.h> #include <gmodule.h> +#define G_UDEV_API_IS_SUBJECT_TO_CHANGE +#include <gudev/gudev.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> #include "mm-manager.h" #include "mm-errors.h" -#include "mm-generic-gsm.h" -#include "mm-generic-cdma.h" #include "mm-plugin.h" static gboolean impl_manager_enumerate_devices (MMManager *manager, @@ -29,9 +29,11 @@ static guint signals[LAST_SIGNAL] = { 0 }; #define MM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MANAGER, MMManagerPrivate)) +#define DBUS_PATH_TAG "dbus-path" + typedef struct { DBusGConnection *connection; - LibHalContext *hal_ctx; + GUdevClient *udev; GSList *plugins; GHashTable *modems; } MMManagerPrivate; @@ -147,169 +149,78 @@ mm_manager_new (DBusGConnection *bus) return manager; } -static char * -get_driver_name (LibHalContext *ctx, const char *udi) -{ - char *parent_udi; - char *driver = NULL; - - parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL); - if (parent_udi) { - driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL); - libhal_free_string (parent_udi); - } - - return driver; -} - -static MMModem * -create_generic_modem (MMManager *manager, const char *udi) -{ - MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); - MMModem *modem; - char **capabilities; - char **iter; - char *serial_device; - char *driver; - gboolean type_gsm = FALSE; - gboolean type_cdma = FALSE; - - capabilities = libhal_device_get_property_strlist (priv->hal_ctx, udi, "modem.command_sets", NULL); - for (iter = capabilities; iter && *iter; iter++) { - if (!strcmp (*iter, "GSM-07.07")) { - type_gsm = TRUE; - break; - } - if (!strcmp (*iter, "IS-707-A")) { - type_cdma = TRUE; - break; - } - } - g_strfreev (capabilities); - - if (!type_gsm && !type_cdma) - return NULL; - - serial_device = libhal_device_get_property_string (priv->hal_ctx, udi, "serial.device", NULL); - g_return_val_if_fail (serial_device != NULL, NULL); - - driver = get_driver_name (priv->hal_ctx, udi); - g_return_val_if_fail (driver != NULL, NULL); - - if (type_gsm) - modem = mm_generic_gsm_new (serial_device, driver); - else - modem = mm_generic_cdma_new (serial_device, driver); - - g_free (serial_device); - g_free (driver); - - if (modem) - g_debug ("Created new generic modem (%s)", udi); - else - g_warning ("Failed to create generic modem (%s)", udi); - - return modem; -} - static void -add_modem (MMManager *manager, const char *udi, MMModem *modem) +remove_modem (MMManager *manager, MMModem *modem) { MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); + char *device; - g_hash_table_insert (priv->modems, g_strdup (udi), modem); - dbus_g_connection_register_g_object (priv->connection, udi, G_OBJECT (modem)); + device = mm_modem_get_device (modem); + g_assert (device); + g_debug ("Removed modem %s", device); - g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem); + g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem); + g_hash_table_remove (priv->modems, device); + g_free (device); } -static MMModem * -modem_exists (MMManager *manager, const char *udi) +static void +modem_valid (MMModem *modem, GParamSpec *pspec, gpointer user_data) { + MMManager *manager = MM_MANAGER (user_data); MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); + static guint32 id = 0; + char *path, *device; - return (MMModem *) g_hash_table_lookup (priv->modems, udi); -} + if (mm_modem_get_valid (modem)) { + 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); -static void -create_initial_modems_from_plugins (MMManager *manager) -{ - MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); - GSList *iter; + device = mm_modem_get_device (modem); + g_assert (device); + g_debug ("Exported modem %s", device); + g_free (device); - for (iter = priv->plugins; iter; iter = iter->next) { - MMPlugin *plugin = MM_PLUGIN (iter->data); - char **udis; - int i; - - udis = mm_plugin_list_supported_udis (plugin, priv->hal_ctx); - if (udis) { - for (i = 0; udis[i]; i++) { - char *udi = udis[i]; - MMModem *modem; - - if (modem_exists (manager, udi)) { - g_warning ("Modem for UDI %s already exists, ignoring", udi); - continue; - } - - modem = mm_plugin_create_modem (plugin, priv->hal_ctx, udi); - if (modem) - add_modem (manager, udi, modem); - } - - g_strfreev (udis); - } - } + g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem); + } else + remove_modem (manager, modem); } static void -create_initial_modems_generic (MMManager *manager) +add_modem (MMManager *manager, MMModem *modem) { MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); - char **devices; - int num_devices; - int i; - DBusError err; - - dbus_error_init (&err); - devices = libhal_find_device_by_capability (priv->hal_ctx, "modem", &num_devices, &err); - if (dbus_error_is_set (&err)) { - g_warning ("Could not list HAL devices: %s", err.message); - dbus_error_free (&err); - } - - if (devices) { - for (i = 0; i < num_devices; i++) { - char *udi = devices[i]; - MMModem *modem; - - if (modem_exists (manager, udi)) - /* Already exists, most likely handled by a plugin */ - continue; - - modem = create_generic_modem (manager, udi); - if (modem) - add_modem (manager, g_strdup (udi), modem); - } + char *device; + gboolean valid = FALSE; + + device = mm_modem_get_device (modem); + g_assert (device); + if (!g_hash_table_lookup (priv->modems, device)) { + g_hash_table_insert (priv->modems, g_strdup (device), modem); + g_debug ("Added modem %s", device); + g_signal_connect (modem, "notify::valid", G_CALLBACK (modem_valid), manager); + g_object_get (modem, MM_MODEM_VALID, &valid, NULL); + if (valid) + modem_valid (modem, NULL, manager); } - - g_strfreev (devices); -} - -static void -create_initial_modems (MMManager *manager) -{ - create_initial_modems_from_plugins (manager); - create_initial_modems_generic (manager); + g_free (device); } static void enumerate_devices_cb (gpointer key, gpointer val, gpointer user_data) { + MMModem *modem = MM_MODEM (val); GPtrArray **devices = (GPtrArray **) user_data; - - g_ptr_array_add (*devices, g_strdup ((char *) key)); + const char *path; + gboolean valid = FALSE; + + g_object_get (G_OBJECT (modem), MM_MODEM_VALID, &valid, NULL); + if (valid) { + path = g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG); + g_return_if_fail (path != NULL); + g_ptr_array_add (*devices, g_strdup (path)); + } } static gboolean @@ -325,118 +236,164 @@ impl_manager_enumerate_devices (MMManager *manager, return TRUE; } +typedef struct { + MMModem *modem; + const char *subsys; + const char *name; +} FindPortInfo; + +static void +find_port (gpointer key, gpointer data, gpointer user_data) +{ + FindPortInfo *info = user_data; + MMModem *modem = MM_MODEM (data); + + if (!info->modem && mm_modem_owns_port (modem, info->subsys, info->name)) + info->modem = modem; +} + +static MMModem * +find_modem_for_port (MMManager *manager, const char *subsys, const char *name) +{ + MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); + FindPortInfo info = { NULL, subsys, name }; + + g_hash_table_foreach (priv->modems, find_port, &info); + return info.modem; +} + static void -device_added (LibHalContext *ctx, const char *udi) +device_added (MMManager *manager, GUdevDevice *device) { - MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx)); MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); GSList *iter; MMModem *modem = NULL; + const char *subsys, *name; + MMPlugin *best_plugin = NULL; + guint32 best_level = 0; + GError *error = NULL; - if (modem_exists (manager, udi)) - /* Shouldn't happen */ + g_return_if_fail (device != NULL); + + subsys = g_udev_device_get_subsystem (device); + name = g_udev_device_get_name (device); + + if (find_modem_for_port (manager, subsys, name)) return; - for (iter = priv->plugins; iter && modem == NULL; iter = iter->next) { + /* Build up the list of plugins that support this port */ + for (iter = priv->plugins; iter; iter = iter->next) { MMPlugin *plugin = MM_PLUGIN (iter->data); + guint32 level; - if (mm_plugin_supports_udi (plugin, ctx, udi)) { - modem = mm_plugin_create_modem (plugin, ctx, udi); - if (modem) - break; + level = mm_plugin_supports_port (plugin, subsys, name); + if (level > best_level) { + best_plugin = plugin; + best_level = level; } } - if (!modem) - /* None of the plugins supported the udi, try generic devices */ - modem = create_generic_modem (manager, udi); + /* Let the best plugin handle this port */ + if (!best_plugin) + return; - if (modem) - add_modem (manager, udi, modem); + modem = mm_plugin_grab_port (best_plugin, subsys, name, &error); + if (modem) { + guint32 modem_type = MM_MODEM_TYPE_UNKNOWN; + const char *type_name = "UNKNOWN"; + + 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"; + + g_message ("(%s): %s modem %s claimed port %s", + mm_plugin_get_name (best_plugin), + type_name, + mm_modem_get_device (modem), + name); + } else { + g_warning ("%s: plugin '%s' claimed to support %s/%s but couldn't: (%d) %s", + __func__, mm_plugin_get_name (best_plugin), subsys, name, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + return; + } + + add_modem (manager, modem); } static void -device_removed (LibHalContext *ctx, const char *udi) +device_removed (MMManager *manager, GUdevDevice *device) { - MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx)); MMModem *modem; + const char *subsys, *name; - modem = modem_exists (manager, udi); - if (modem) { - g_debug ("Removed modem %s", udi); - g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem); - g_hash_table_remove (MM_MANAGER_GET_PRIVATE (manager)->modems, udi); - } + g_return_if_fail (device != NULL); + + subsys = g_udev_device_get_subsystem (device); + name = g_udev_device_get_name (device); + modem = find_modem_for_port (manager, subsys, name); + if (modem) + mm_modem_release_port (modem, subsys, name); } static void -device_new_capability (LibHalContext *ctx, const char *udi, const char *capability) +handle_uevent (GUdevClient *client, + const char *action, + GUdevDevice *device, + gpointer user_data) { - device_added (ctx, udi); -} + MMManager *self = MM_MANAGER (user_data); + const char *subsys; + g_return_if_fail (action != NULL); -DBusGConnection * -mm_manager_get_bus (MMManager *manager) -{ - g_return_val_if_fail (MM_IS_MANAGER (manager), NULL); - - return MM_MANAGER_GET_PRIVATE (manager)->connection; -} + /* A bit paranoid */ + subsys = g_udev_device_get_subsystem (device); + g_return_if_fail (subsys != NULL); -static gboolean -remove_one (gpointer key, - gpointer value, - gpointer user_data) -{ - const char *udi = (char *) key; - MMModem *modem = MM_MODEM (value); - MMManager *manager = MM_MANAGER (user_data); + g_return_if_fail (!strcmp (subsys, "tty") || !strcmp (subsys, "net")); - g_debug ("Removed modem %s", udi); - g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem); - - return TRUE; + if (!strcmp (action, "add")) + device_added (self, device); + else if (!strcmp (action, "remove")) + device_removed (self, device); } void -mm_manager_set_hal_ctx (MMManager *manager, - LibHalContext *hal_ctx) +mm_manager_start (MMManager *manager) { MMManagerPrivate *priv; + GList *devices, *iter; + g_return_if_fail (manager != NULL); g_return_if_fail (MM_IS_MANAGER (manager)); priv = MM_MANAGER_GET_PRIVATE (manager); - priv->hal_ctx = hal_ctx; - if (hal_ctx) { - libhal_ctx_set_user_data (hal_ctx, manager); - libhal_ctx_set_device_added (hal_ctx, device_added); - libhal_ctx_set_device_removed (hal_ctx, device_removed); - libhal_ctx_set_device_new_capability (hal_ctx, device_new_capability); + devices = g_udev_client_query_by_subsystem (priv->udev, "tty"); + for (iter = devices; iter; iter = g_list_next (iter)) + device_added (manager, G_UDEV_DEVICE (iter->data)); - create_initial_modems (manager); - } else { - g_hash_table_foreach_remove (priv->modems, remove_one, manager); - } -} - -LibHalContext * -mm_manager_get_hal_ctx (MMManager *manager) -{ - g_return_val_if_fail (MM_IS_MANAGER (manager), NULL); - - return MM_MANAGER_GET_PRIVATE (manager)->hal_ctx; + devices = g_udev_client_query_by_subsystem (priv->udev, "net"); + for (iter = devices; iter; iter = g_list_next (iter)) + device_added (manager, G_UDEV_DEVICE (iter->data)); } static void mm_manager_init (MMManager *manager) { MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); + const char *subsys[3] = { "tty", "net", NULL }; priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); load_plugins (manager); + + priv->udev = g_udev_client_new (subsys); + g_assert (priv->udev); + g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager); } static void @@ -449,11 +406,8 @@ finalize (GObject *object) g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL); g_slist_free (priv->plugins); - if (priv->hal_ctx) { - mm_manager_set_hal_ctx (MM_MANAGER (object), NULL); - libhal_ctx_shutdown (priv->hal_ctx, NULL); - libhal_ctx_free (priv->hal_ctx); - } + if (priv->udev) + g_object_unref (priv->udev); if (priv->connection) dbus_g_connection_unref (priv->connection); |