diff options
Diffstat (limited to 'src/mm-base-manager.c')
-rw-r--r-- | src/mm-base-manager.c | 231 |
1 files changed, 54 insertions, 177 deletions
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c index cdc5d54a..9da38960 100644 --- a/src/mm-base-manager.c +++ b/src/mm-base-manager.c @@ -12,15 +12,16 @@ * * Copyright (C) 2008 - 2009 Novell, Inc. * Copyright (C) 2009 - 2012 Red Hat, Inc. - * Copyright (C) 2011 - 2012 Aleksander Morgado <aleksander@gnu.org> - * Copyright (C) 2011 - 2012 Google, Inc. + * Copyright (C) 2011 - 2012 Google, Inc + * Copyright (C) 2016 Velocloud, Inc. + * Copyright (C) 2011 - 2016 Aleksander Morgado <aleksander@aleksander.es> */ #include <string.h> #include <ctype.h> #include <gmodule.h> -#include <gudev/gudev.h> +#include "mm-kernel-device-udev.h" #include <ModemManager.h> #include <mm-errors-types.h> @@ -94,8 +95,8 @@ find_device_by_modem (MMBaseManager *manager, } static MMDevice * -find_device_by_port (MMBaseManager *manager, - GUdevDevice *port) +find_device_by_port (MMBaseManager *manager, + MMKernelDevice *port) { GHashTableIter iter; gpointer key, value; @@ -118,10 +119,10 @@ find_device_by_physdev_uid (MMBaseManager *self, } static MMDevice * -find_device_by_udev_device (MMBaseManager *manager, - GUdevDevice *udev_device) +find_device_by_kernel_device (MMBaseManager *manager, + MMKernelDevice *kernel_device) { - return find_device_by_physdev_uid (manager, g_udev_device_get_sysfs_path (udev_device)); + return find_device_by_physdev_uid (manager, mm_kernel_device_get_physdev_uid (kernel_device)); } /*****************************************************************************/ @@ -175,100 +176,26 @@ device_support_check_ready (MMPluginManager *plugin_manager, find_device_support_context_free (ctx); } -static GUdevDevice * -find_physical_device (GUdevDevice *child) -{ - GUdevDevice *iter, *old = NULL; - GUdevDevice *physdev = NULL; - const char *subsys, *type, *name; - guint32 i = 0; - gboolean is_usb = FALSE, is_pci = FALSE, is_pcmcia = FALSE, is_platform = FALSE; - gboolean is_pnp = FALSE; - - g_return_val_if_fail (child != NULL, NULL); - - /* Bluetooth rfcomm devices are "virtual" and don't necessarily have - * parents at all. - */ - name = g_udev_device_get_name (child); - if (name && strncmp (name, "rfcomm", 6) == 0) - return g_object_ref (child); - - iter = g_object_ref (child); - while (iter && i++ < 8) { - subsys = g_udev_device_get_subsystem (iter); - if (subsys) { - if (is_usb || g_str_has_prefix (subsys, "usb")) { - is_usb = TRUE; - type = g_udev_device_get_devtype (iter); - if (type && !strcmp (type, "usb_device")) { - physdev = iter; - break; - } - } else if (is_pcmcia || !strcmp (subsys, "pcmcia")) { - GUdevDevice *pcmcia_parent; - const char *tmp_subsys; - - is_pcmcia = TRUE; - - /* If the parent of this PCMCIA device is no longer part of - * the PCMCIA subsystem, we want to stop since we're looking - * for the base PCMCIA device, not the PCMCIA controller which - * is usually PCI or some other bus type. - */ - pcmcia_parent = g_udev_device_get_parent (iter); - if (pcmcia_parent) { - tmp_subsys = g_udev_device_get_subsystem (pcmcia_parent); - if (tmp_subsys && strcmp (tmp_subsys, "pcmcia")) - physdev = iter; - g_object_unref (pcmcia_parent); - if (physdev) - break; - } - } else if (is_platform || !strcmp (subsys, "platform")) { - /* Take the first platform parent as the physical device */ - is_platform = TRUE; - physdev = iter; - break; - } else if (is_pci || !strcmp (subsys, "pci")) { - is_pci = TRUE; - physdev = iter; - break; - } else if (is_pnp || !strcmp (subsys, "pnp")) { - is_pnp = TRUE; - physdev = iter; - break; - } - } - - old = iter; - iter = g_udev_device_get_parent (old); - g_object_unref (old); - } - - return physdev; -} - static void -device_removed (MMBaseManager *self, - GUdevDevice *udev_device) +device_removed (MMBaseManager *self, + MMKernelDevice *kernel_device) { MMDevice *device; const gchar *subsys; const gchar *name; - g_return_if_fail (udev_device != NULL); + g_return_if_fail (kernel_device != NULL); - subsys = g_udev_device_get_subsystem (udev_device); - name = g_udev_device_get_name (udev_device); + subsys = mm_kernel_device_get_subsystem (kernel_device); + name = mm_kernel_device_get_name (kernel_device); if (!g_str_has_prefix (subsys, "usb") || (name && g_str_has_prefix (name, "cdc-wdm"))) { /* Handle tty/net/wdm port removal */ - device = find_device_by_port (self, udev_device); + device = find_device_by_port (self, kernel_device); if (device) { mm_info ("(%s/%s): released by device '%s'", subsys, name, mm_device_get_uid (device)); - mm_device_release_port (device, udev_device); + mm_device_release_port (device, kernel_device); /* If port probe list gets empty, remove the device object iself */ if (!mm_device_peek_port_probe_list (device)) { @@ -291,105 +218,49 @@ device_removed (MMBaseManager *self, * device has been removed. That way, if the device is reinserted later, we'll go through * the process of exporting it. */ - device = find_device_by_udev_device (self, udev_device); + device = find_device_by_kernel_device (self, kernel_device); if (device) { mm_dbg ("Removing device '%s'", mm_device_get_uid (device)); mm_device_remove_modem (device); g_hash_table_remove (self->priv->devices, mm_device_get_uid (device)); return; } - - /* Maybe a plugin is checking whether or not the port is supported. - * TODO: Cancel every possible supports check in this port. */ } static void -device_added (MMBaseManager *manager, - GUdevDevice *port, - gboolean hotplugged, - gboolean manual_scan) +device_added (MMBaseManager *manager, + MMKernelDevice *port, + gboolean hotplugged, + gboolean manual_scan) { - MMDevice *device; - const char *subsys, *name, *physdev_uid, *physdev_subsys; - gboolean is_candidate; - GUdevDevice *physdev = NULL; + MMDevice *device; + const gchar *physdev_uid; g_return_if_fail (port != NULL); - subsys = g_udev_device_get_subsystem (port); - name = g_udev_device_get_name (port); - - /* ignore VTs */ - if (strncmp (name, "tty", 3) == 0 && isdigit (name[3])) - return; - - /* Ignore devices that aren't completely configured by udev yet. If - * ModemManager is started in parallel with udev, explicitly requesting - * devices may return devices for which not all udev rules have yet been - * applied (a bug in udev/gudev). Since we often need those rules to match - * the device to a specific ModemManager driver, we need to ensure that all - * rules have been processed before handling a device. - */ - is_candidate = g_udev_device_get_property_as_boolean (port, "ID_MM_CANDIDATE"); - if (!is_candidate) { - /* This could mean that device changed, loosing its ID_MM_CANDIDATE + if (!mm_kernel_device_is_candidate (port, manual_scan)) { + /* This could mean that device changed, losing its ID_MM_CANDIDATE * flags (such as Bluetooth RFCOMM devices upon disconnect. * Try to forget it. */ - if (hotplugged && !manual_scan) - device_removed (manager, port); + device_removed (manager, port); + mm_dbg ("(%s/%s): port not candidate", + mm_kernel_device_get_subsystem (port), + mm_kernel_device_get_name (port)); return; } - if (find_device_by_port (manager, port)) + /* If already added, ignore new event */ + if (find_device_by_port (manager, port)) { + mm_dbg ("(%s/%s): port already added", + mm_kernel_device_get_subsystem (port), + mm_kernel_device_get_name (port)); return; - - /* 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. - */ - physdev = find_physical_device (port); - if (!physdev) { - /* Warn about it, but filter out some common ports that we know don't have - * anything to do with mobile broadband. - */ - if ( strcmp (name, "console") - && strcmp (name, "ptmx") - && strcmp (name, "lo") - && strcmp (name, "tty") - && !strstr (name, "virbr")) - mm_dbg ("(%s/%s): could not get port's parent device", subsys, name); - - goto out; - } - - /* Is the device blacklisted? */ - if (g_udev_device_get_property_as_boolean (physdev, "ID_MM_DEVICE_IGNORE")) { - mm_dbg ("(%s/%s): port's parent device is blacklisted", subsys, name); - goto out; } - /* Is the device in the manual-only greylist? If so, return if this is an - * automatic scan. */ - if (!manual_scan && g_udev_device_get_property_as_boolean (physdev, "ID_MM_DEVICE_MANUAL_SCAN_ONLY")) { - mm_dbg ("(%s/%s): port probed only in manual scan", subsys, name); - goto out; - } - - /* If the physdev is a 'platform' or 'pnp' device that's not whitelisted, ignore it */ - physdev_subsys = g_udev_device_get_subsystem (physdev); - if ( physdev_subsys - && ( g_str_equal (physdev_subsys, "platform") - || g_str_equal (physdev_subsys, "pnp")) - && !g_udev_device_get_property_as_boolean (physdev, "ID_MM_PLATFORM_DRIVER_PROBE")) { - mm_dbg ("(%s/%s): port's parent platform driver is not whitelisted", subsys, name); - goto out; - } - - physdev_uid = g_udev_device_get_sysfs_path (physdev); - if (!physdev_uid) { - mm_dbg ("(%s/%s): could not get port's parent device sysfs path", subsys, name); - goto out; - } + /* Get the port's physical device's uid. All ports of the same physical + * device will share the same uid. */ + physdev_uid = mm_kernel_device_get_physdev_uid (port); + g_assert (physdev_uid); /* See if we already created an object to handle ports in this device */ device = find_device_by_physdev_uid (manager, physdev_uid); @@ -397,7 +268,7 @@ device_added (MMBaseManager *manager, FindDeviceSupportContext *ctx; /* Keep the device listed in the Manager */ - device = mm_device_new (physdev, hotplugged); + device = mm_device_new (physdev_uid, hotplugged, FALSE); g_hash_table_insert (manager->priv->devices, g_strdup (physdev_uid), device); @@ -415,10 +286,6 @@ device_added (MMBaseManager *manager, /* Grab the port in the existing device. */ mm_device_grab_port (device, port); - -out: - if (physdev) - g_object_unref (physdev); } static void @@ -430,6 +297,7 @@ handle_uevent (GUdevClient *client, MMBaseManager *self = MM_BASE_MANAGER (user_data); const gchar *subsys; const gchar *name; + MMKernelDevice *kernel_device; g_return_if_fail (action != NULL); @@ -438,15 +306,19 @@ handle_uevent (GUdevClient *client, g_return_if_fail (subsys != NULL); g_return_if_fail (g_str_equal (subsys, "tty") || g_str_equal (subsys, "net") || g_str_has_prefix (subsys, "usb")); + kernel_device = mm_kernel_device_udev_new (device); + /* We only care about tty/net and usb/cdc-wdm devices when adding modem ports, * but for remove, also handle usb parent device remove events */ - name = g_udev_device_get_name (device); + name = mm_kernel_device_get_name (kernel_device); if ( (g_str_equal (action, "add") || g_str_equal (action, "move") || g_str_equal (action, "change")) && (!g_str_has_prefix (subsys, "usb") || (name && g_str_has_prefix (name, "cdc-wdm")))) - device_added (self, device, TRUE, FALSE); + device_added (self, kernel_device, TRUE, FALSE); else if (g_str_equal (action, "remove")) - device_removed (self, device); + device_removed (self, kernel_device); + + g_object_unref (kernel_device); } typedef struct { @@ -458,7 +330,12 @@ typedef struct { static gboolean start_device_added_idle (StartDeviceAdded *ctx) { - device_added (ctx->self, ctx->device, FALSE, ctx->manual_scan); + MMKernelDevice *kernel_device; + + kernel_device = mm_kernel_device_udev_new (ctx->device); + device_added (ctx->self, kernel_device, FALSE, ctx->manual_scan); + g_object_unref (kernel_device); + g_object_unref (ctx->self); g_object_unref (ctx->device); g_slice_free (StartDeviceAdded, ctx); @@ -757,7 +634,7 @@ handle_set_profile (MmGdbusTest *skeleton, /* Create device and keep it listed in the Manager */ physdev_uid = g_strdup_printf ("/virtual/%s", id); - device = mm_device_virtual_new (physdev_uid, TRUE); + device = mm_device_new (physdev_uid, TRUE, TRUE); g_hash_table_insert (self->priv->devices, physdev_uid, device); /* Grab virtual ports */ |