diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2014-10-01 12:00:14 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2014-11-01 20:07:35 +0100 |
commit | f79ec9bf4d94a6ae204e24647bf844d6af2ecb96 (patch) | |
tree | b269a0e7e79affbbc29799b5de0ad3a80ce638c3 /src | |
parent | b8cd5ae838b1a17ce1bb6f01e6491c7b887e8474 (diff) |
manager: Remove devices which are deemed unfit during addition attempt
device_added() might be called in response to a "change" or "move" attempt that
might have changed a candidate device to a non-candidate one.
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-base-manager.c | 118 |
1 files changed, 62 insertions, 56 deletions
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c index 3900af5b..f5d4e286 100644 --- a/src/mm-base-manager.c +++ b/src/mm-base-manager.c @@ -240,6 +240,61 @@ find_physical_device (GUdevDevice *child) } static void +device_removed (MMBaseManager *self, + GUdevDevice *udev_device) +{ + MMDevice *device; + const gchar *subsys; + const gchar *name; + + g_return_if_fail (udev_device != NULL); + + subsys = g_udev_device_get_subsystem (udev_device); + name = g_udev_device_get_name (udev_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); + if (device) { + mm_info ("(%s/%s): released by modem %s", + subsys, + name, + g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device))); + mm_device_release_port (device, udev_device); + + /* If port probe list gets empty, remove the device object iself */ + if (!mm_device_peek_port_probe_list (device)) { + mm_dbg ("Removing empty device '%s'", mm_device_get_path (device)); + mm_device_remove_modem (device); + g_hash_table_remove (self->priv->devices, mm_device_get_path (device)); + } + } + + return; + } + + /* This case is designed to handle the case where, at least with kernel 2.6.31, unplugging + * an in-use ttyACMx device results in udev generating remove events for the usb, but the + * ttyACMx device (subsystem tty) is not removed, since it was in-use. So if we have not + * found a modem for the port (above), we're going to look here to see if we have a modem + * associated with the newly removed device. If so, we'll remove the modem, since the + * 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); + if (device) { + mm_dbg ("Removing device '%s'", mm_device_get_path (device)); + mm_device_remove_modem (device); + g_hash_table_remove (self->priv->devices, mm_device_get_path (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, @@ -267,8 +322,14 @@ device_added (MMBaseManager *manager, * rules have been processed before handling a device. */ is_candidate = g_udev_device_get_property_as_boolean (port, "ID_MM_CANDIDATE"); - if (!is_candidate) + if (!is_candidate) { + /* This could mean that device changed, loosing its ID_MM_CANDIDATE + * flags (such as Bluetooth RFCOMM devices upon disconnect. + * Try to forget it. */ + if (hotplugged && !manual_scan) + device_removed (manager, port); return; + } if (find_device_by_port (manager, port)) return; @@ -352,61 +413,6 @@ out: } static void -device_removed (MMBaseManager *self, - GUdevDevice *udev_device) -{ - MMDevice *device; - const gchar *subsys; - const gchar *name; - - g_return_if_fail (udev_device != NULL); - - subsys = g_udev_device_get_subsystem (udev_device); - name = g_udev_device_get_name (udev_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); - if (device) { - mm_info ("(%s/%s): released by modem %s", - subsys, - name, - g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device))); - mm_device_release_port (device, udev_device); - - /* If port probe list gets empty, remove the device object iself */ - if (!mm_device_peek_port_probe_list (device)) { - mm_dbg ("Removing empty device '%s'", mm_device_get_path (device)); - mm_device_remove_modem (device); - g_hash_table_remove (self->priv->devices, mm_device_get_path (device)); - } - } - - return; - } - - /* This case is designed to handle the case where, at least with kernel 2.6.31, unplugging - * an in-use ttyACMx device results in udev generating remove events for the usb, but the - * ttyACMx device (subsystem tty) is not removed, since it was in-use. So if we have not - * found a modem for the port (above), we're going to look here to see if we have a modem - * associated with the newly removed device. If so, we'll remove the modem, since the - * 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); - if (device) { - mm_dbg ("Removing device '%s'", mm_device_get_path (device)); - mm_device_remove_modem (device); - g_hash_table_remove (self->priv->devices, mm_device_get_path (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 handle_uevent (GUdevClient *client, const char *action, GUdevDevice *device, |