base-manager: reprobe device on late port additions
There is no guarantee from the kernel that the ports of a given device will all be notified via uevents on a timely manner. We assume it, but we cannot be completely sure. There are two main scenarios that we have been seen when the ports of a device are not notified close enough to each other: * A modem object is created, but not with the desired control protocol. E.g. a QMI or MBIM modem would end up controlled via AT commands if the cdc-wdm port was added too late. * A modem object is not created at all, and the device object was removed completely. E.g. when the net port addition in a QMI or MBIM modem happens too late. In order to avoid those cases, we will now fully reprobe all the ports of the device from scratch whenever a new valid port addition happens after the initial probing of the device has already been completed. If a modem object is available at that time, we will remove it right away.
This commit is contained in:
+184
-46
@@ -206,34 +206,31 @@ device_support_check_ready (MMPluginManager *plugin_manager,
|
||||
GAsyncResult *res,
|
||||
FindDeviceSupportContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
MMPlugin *plugin;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(MMPlugin) plugin = NULL;
|
||||
|
||||
/* If the device support check fails, either with an error, or afterwards
|
||||
* when trying to create a modem object, we must remove the MMDevice from
|
||||
* the tracking table of devices, so that a manual scan request afterwards
|
||||
* re-scans all ports. */
|
||||
* when trying to create a modem object, we must reset the port probe list
|
||||
* in the MMDevice, so that a manual scan request afterwards re-scans all
|
||||
* ports. */
|
||||
|
||||
/* Receive plugin result from the plugin manager */
|
||||
plugin = mm_plugin_manager_device_support_check_finish (plugin_manager, res, &error);
|
||||
if (!plugin) {
|
||||
mm_obj_msg (ctx->self, "couldn't check support for device '%s': %s",
|
||||
mm_device_get_uid (ctx->device), error->message);
|
||||
g_error_free (error);
|
||||
g_hash_table_remove (ctx->self->priv->devices, mm_device_get_uid (ctx->device));
|
||||
mm_device_reset_port_probe_list (ctx->device);
|
||||
find_device_support_context_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the plugin as the one expected in the device */
|
||||
mm_device_set_plugin (ctx->device, G_OBJECT (plugin));
|
||||
g_object_unref (plugin);
|
||||
|
||||
if (!mm_device_create_modem (ctx->device, &error)) {
|
||||
mm_obj_warn (ctx->self, "couldn't create modem for device '%s': %s",
|
||||
mm_device_get_uid (ctx->device), error->message);
|
||||
g_error_free (error);
|
||||
g_hash_table_remove (ctx->self->priv->devices, mm_device_get_uid (ctx->device));
|
||||
mm_device_reset_port_probe_list (ctx->device);
|
||||
find_device_support_context_free (ctx);
|
||||
return;
|
||||
}
|
||||
@@ -296,6 +293,167 @@ device_removed (MMBaseManager *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_support_check_add_all_ports (MMBaseManager *self,
|
||||
MMDevice *device)
|
||||
{
|
||||
FindDeviceSupportContext *ctx;
|
||||
GList *l;
|
||||
|
||||
g_assert (!mm_plugin_manager_device_support_check_ongoing (self->priv->plugin_manager, device));
|
||||
|
||||
/* There is no running device support context, so we launch a new one */
|
||||
ctx = g_slice_new (FindDeviceSupportContext);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->device = g_object_ref (device);
|
||||
mm_plugin_manager_device_support_check (self->priv->plugin_manager,
|
||||
device,
|
||||
(GAsyncReadyCallback) device_support_check_ready,
|
||||
ctx);
|
||||
|
||||
g_assert (mm_plugin_manager_device_support_check_ongoing (self->priv->plugin_manager, device));
|
||||
|
||||
/* Iterate all known ports and notify them one by one */
|
||||
for (l = mm_device_peek_port_probe_list (device); l; l = g_list_next (l)) {
|
||||
mm_plugin_manager_device_support_check_add_port (self->priv->plugin_manager,
|
||||
device,
|
||||
mm_port_probe_peek_port (MM_PORT_PROBE (l->data)));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_support_check_add_single_port (MMBaseManager *self,
|
||||
MMDevice *device,
|
||||
MMKernelDevice *port)
|
||||
{
|
||||
FindDeviceSupportContext *ctx;
|
||||
gboolean added;
|
||||
|
||||
/* Try to add the port to an already running device support context */
|
||||
if (mm_plugin_manager_device_support_check_add_port (self->priv->plugin_manager, device, port))
|
||||
return;
|
||||
|
||||
/* There is no running device support context, so we launch a new one */
|
||||
ctx = g_slice_new (FindDeviceSupportContext);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->device = g_object_ref (device);
|
||||
mm_plugin_manager_device_support_check (self->priv->plugin_manager,
|
||||
device,
|
||||
(GAsyncReadyCallback) device_support_check_ready,
|
||||
ctx);
|
||||
|
||||
/* Retry now, which should never fail */
|
||||
added = mm_plugin_manager_device_support_check_add_port (self->priv->plugin_manager, device, port);
|
||||
g_assert (added);
|
||||
}
|
||||
|
||||
static void
|
||||
existing_port (MMBaseManager *self,
|
||||
MMDevice *device,
|
||||
MMKernelDevice *port)
|
||||
{
|
||||
const gchar *name;
|
||||
const gchar *uid;
|
||||
|
||||
name = mm_kernel_device_get_name (port);
|
||||
uid = mm_device_get_uid (device);
|
||||
|
||||
mm_obj_dbg (self, "port %s already available in device '%s'", name, uid);
|
||||
|
||||
/* If the port exists already in the device, and we already have a valid modem
|
||||
* object created, there is no point in processing this event, we can warn about
|
||||
* the situation and bail out. This may happen e.g. if a manual scan is requested
|
||||
* after having successfully finished the last probing operation. */
|
||||
if (mm_device_peek_plugin (device) && mm_device_peek_modem (device)) {
|
||||
mm_obj_dbg (self, "ignoring port %s as device '%s' already has a valid modem", name, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The port exists in the device, but we don't have a valid modem associated with
|
||||
* it. This may happen if a manual scan is requested after having failed the last
|
||||
* device probing operation. We need to relaunch a new device probing task, unless
|
||||
* one is already running. */
|
||||
device_support_check_add_single_port (self, device, port);
|
||||
}
|
||||
|
||||
static void
|
||||
additional_port (MMBaseManager *self,
|
||||
MMDevice *device,
|
||||
MMKernelDevice *port)
|
||||
{
|
||||
MMBaseModem *modem;
|
||||
const gchar *name;
|
||||
const gchar *uid;
|
||||
|
||||
name = mm_kernel_device_get_name (port);
|
||||
uid = mm_device_get_uid (device);
|
||||
|
||||
mm_obj_dbg (self, "additional port %s in device '%s'", name, uid);
|
||||
|
||||
/* Do nothing if the device is ignoring the new port */
|
||||
if (!mm_device_grab_port (device, port))
|
||||
return;
|
||||
|
||||
/* If there is an ongoing support check, we can add the single port right away */
|
||||
if (mm_plugin_manager_device_support_check_ongoing (self->priv->plugin_manager, device)) {
|
||||
device_support_check_add_single_port (self, device, port);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_warn (self, "additional port %s in device '%s' added after device probing has already finished", name, uid);
|
||||
|
||||
/* If there is no plugin assigned in the device, it means the device probing had failed earlier,
|
||||
* for example if none of the ports that were used for the device probing were usable control ports */
|
||||
if (!mm_device_peek_plugin (device)) {
|
||||
g_assert (!mm_device_peek_modem (device));
|
||||
mm_obj_info (self, "last device '%s' probing had failed, will retry", uid);
|
||||
device_support_check_add_all_ports (self, device);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is no modem object assigned to the device, it means the modem object creation had failed earlier,
|
||||
* for example if a required port was missing (e.g. missing net port in a QMI or MBIM modem) */
|
||||
modem = mm_device_peek_modem (device);
|
||||
if (!modem) {
|
||||
mm_obj_info (self, "last modem object creation in device '%s' had failed, will retry", uid);
|
||||
device_support_check_add_all_ports (self, device);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_info (self, "last modem object creation in device '%s' succeeded, but we have a new port addition, will retry", uid);
|
||||
g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
|
||||
mm_device_remove_modem (device);
|
||||
device_support_check_add_all_ports (self, device);
|
||||
}
|
||||
|
||||
static void
|
||||
first_port (MMBaseManager *self,
|
||||
MMKernelDevice *port,
|
||||
gboolean hotplugged)
|
||||
{
|
||||
g_autoptr(MMDevice) device = NULL;
|
||||
const gchar *name;
|
||||
const gchar *uid;
|
||||
const gchar *physdev;
|
||||
|
||||
name = mm_kernel_device_get_name (port);
|
||||
uid = mm_kernel_device_get_physdev_uid (port);
|
||||
|
||||
mm_obj_dbg (self, "port %s is first in device '%s'", name, uid);
|
||||
|
||||
physdev = mm_kernel_device_get_physdev_sysfs_path (port);
|
||||
device = mm_device_new (uid, physdev, hotplugged, FALSE, self->priv->object_manager);
|
||||
|
||||
/* If the device is ignoring the new port, discard the new device as well */
|
||||
if (!mm_device_grab_port (device, port)) {
|
||||
mm_obj_dbg (self, "discarding device '%s' as the first port is not grabbed", uid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the device */
|
||||
g_hash_table_insert (self->priv->devices, g_strdup (uid), g_steal_pointer (&device));
|
||||
}
|
||||
|
||||
static void
|
||||
device_added (MMBaseManager *self,
|
||||
MMKernelDevice *port,
|
||||
@@ -303,8 +461,8 @@ device_added (MMBaseManager *self,
|
||||
gboolean manual_scan)
|
||||
{
|
||||
MMDevice *device;
|
||||
const gchar *physdev_uid;
|
||||
const gchar *name;
|
||||
const gchar *uid;
|
||||
|
||||
g_return_if_fail (port != NULL);
|
||||
|
||||
@@ -333,15 +491,15 @@ device_added (MMBaseManager *self,
|
||||
|
||||
/* 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);
|
||||
uid = mm_kernel_device_get_physdev_uid (port);
|
||||
g_assert (uid);
|
||||
|
||||
/* If the device is inhibited, do nothing else */
|
||||
if (is_device_inhibited (self, physdev_uid)) {
|
||||
if (is_device_inhibited (self, uid)) {
|
||||
/* Note: we will not report as hotplugged an inhibited device port
|
||||
* because we don't know what was done with the port out of our
|
||||
* context. */
|
||||
device_inhibited_track_port (self, physdev_uid, port, manual_scan);
|
||||
device_inhibited_track_port (self, uid, port, manual_scan);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -349,42 +507,22 @@ device_added (MMBaseManager *self,
|
||||
if (!mm_filter_port (self->priv->filter, port, manual_scan))
|
||||
return;
|
||||
|
||||
/* If already added, ignore new event */
|
||||
if (find_device_by_port (self, port)) {
|
||||
mm_obj_dbg (self, "port %s already added", name);
|
||||
/* If the port is already added, don't add it again */
|
||||
device = find_device_by_port (self, port);
|
||||
if (device) {
|
||||
existing_port (self, device, port);
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if we already created an object to handle ports in this device */
|
||||
device = find_device_by_physdev_uid (self, physdev_uid);
|
||||
if (!device) {
|
||||
const gchar *physdev;
|
||||
FindDeviceSupportContext *ctx;
|
||||
device = find_device_by_physdev_uid (self, uid);
|
||||
if (device) {
|
||||
additional_port (self, device, port);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "port %s is first in device %s", name, physdev_uid);
|
||||
|
||||
physdev = mm_kernel_device_get_physdev_sysfs_path (port);
|
||||
|
||||
/* Keep the device listed in the Manager */
|
||||
device = mm_device_new (physdev_uid, physdev, hotplugged, FALSE, self->priv->object_manager);
|
||||
g_hash_table_insert (self->priv->devices,
|
||||
g_strdup (physdev_uid),
|
||||
device);
|
||||
|
||||
/* Launch device support check */
|
||||
ctx = g_slice_new (FindDeviceSupportContext);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->device = g_object_ref (device);
|
||||
mm_plugin_manager_device_support_check (
|
||||
self->priv->plugin_manager,
|
||||
device,
|
||||
(GAsyncReadyCallback) device_support_check_ready,
|
||||
ctx);
|
||||
} else
|
||||
mm_obj_dbg (self, "additional port %s in device %s", name, physdev_uid);
|
||||
|
||||
/* Grab the port in the existing device. */
|
||||
mm_device_grab_port (device, port);
|
||||
/* This is the first port in a new device */
|
||||
first_port (self, port, hotplugged);
|
||||
}
|
||||
|
||||
#if defined WITH_QRTR
|
||||
|
||||
+21
-22
@@ -10,7 +10,7 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc.
|
||||
* Copyright (C) 2012-2024 Google, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "mm-device.h"
|
||||
#include "mm-plugin.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-daemon-enums-types.h"
|
||||
|
||||
static void log_object_iface_init (MMLogObjectInterface *iface);
|
||||
|
||||
@@ -46,7 +47,6 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
SIGNAL_PORT_GRABBED,
|
||||
SIGNAL_PORT_RELEASED,
|
||||
SIGNAL_LAST
|
||||
};
|
||||
@@ -76,7 +76,8 @@ struct _MMDevicePrivate {
|
||||
/* Kernel drivers managing this device */
|
||||
gchar **drivers;
|
||||
|
||||
/* Best plugin to manage this device */
|
||||
/* Best plugin to manage this device, only if the device probing
|
||||
* has finished successfully. */
|
||||
MMPlugin *plugin;
|
||||
|
||||
/* Lists of port probes in the device */
|
||||
@@ -213,7 +214,7 @@ add_port_driver (MMDevice *self,
|
||||
self->priv->drivers[n_items + 1] = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
mm_device_grab_port (MMDevice *self,
|
||||
MMKernelDevice *kernel_port)
|
||||
{
|
||||
@@ -221,22 +222,19 @@ mm_device_grab_port (MMDevice *self,
|
||||
MMKernelDevice *lower_port;
|
||||
|
||||
if (mm_device_owns_port (self, kernel_port))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
lower_port = mm_kernel_device_peek_lower_device (kernel_port);
|
||||
if (lower_port) {
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
/* No port probing done, at this point this is not something we require
|
||||
* as all the virtual instantiated ports are net devices. We also avoid
|
||||
* emitting the PORT_GRABBED signal in the MMDevice, because that is
|
||||
* exclusively linked to a port being added to the list of probes, which
|
||||
* we don't do here. */
|
||||
* as all the virtual instantiated ports are net devices. */
|
||||
if (self->priv->modem && !mm_base_modem_grab_link_port (self->priv->modem, kernel_port, &error))
|
||||
mm_obj_dbg (self, "fully ignoring link port %s from now on: %s",
|
||||
mm_kernel_device_get_name (kernel_port),
|
||||
error->message);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
if (!g_strcmp0 ("net", mm_kernel_device_get_subsystem (kernel_port)) &&
|
||||
mm_kernel_device_get_wwandev_sysfs_path (kernel_port)) {
|
||||
@@ -256,7 +254,7 @@ mm_device_grab_port (MMDevice *self,
|
||||
mm_obj_dbg (self, "fully ignoring link port %s from now on: %s",
|
||||
mm_kernel_device_get_name (kernel_port),
|
||||
error->message);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +276,7 @@ mm_device_grab_port (MMDevice *self,
|
||||
probe = mm_port_probe_new (self, kernel_port);
|
||||
self->priv->port_probes = g_list_prepend (self->priv->port_probes, probe);
|
||||
|
||||
/* Notify about the grabbed port */
|
||||
g_signal_emit (self, signals[SIGNAL_PORT_GRABBED], 0, kernel_port);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -627,6 +624,17 @@ mm_device_peek_port_probe_list (MMDevice *self)
|
||||
return self->priv->port_probes;
|
||||
}
|
||||
|
||||
void
|
||||
mm_device_reset_port_probe_list (MMDevice *self)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
mm_obj_dbg (self, "port probe list reset...");
|
||||
for (l = self->priv->port_probes; l; l = g_list_next (l)) {
|
||||
mm_port_probe_reset (MM_PORT_PROBE (l->data));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_device_get_hotplugged (MMDevice *self)
|
||||
{
|
||||
@@ -981,15 +989,6 @@ mm_device_class_init (MMDeviceClass *klass)
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (object_class, PROP_INHIBITED, properties[PROP_INHIBITED]);
|
||||
|
||||
signals[SIGNAL_PORT_GRABBED] =
|
||||
g_signal_new (MM_DEVICE_PORT_GRABBED,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (MMDeviceClass, port_grabbed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_generic,
|
||||
G_TYPE_NONE, 1, MM_TYPE_KERNEL_DEVICE);
|
||||
|
||||
signals[SIGNAL_PORT_RELEASED] =
|
||||
g_signal_new (MM_DEVICE_PORT_RELEASED,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
|
||||
+9
-11
@@ -10,7 +10,7 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc.
|
||||
* Copyright (C) 2012-2024 Google, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MM_DEVICE_H
|
||||
@@ -42,7 +42,6 @@ typedef struct _MMDevicePrivate MMDevicePrivate;
|
||||
#define MM_DEVICE_INHIBITED "inhibited"
|
||||
#define MM_DEVICE_OBJECT_MANAGER "object-manager"
|
||||
|
||||
#define MM_DEVICE_PORT_GRABBED "port-grabbed"
|
||||
#define MM_DEVICE_PORT_RELEASED "port-released"
|
||||
|
||||
struct _MMDevice {
|
||||
@@ -54,8 +53,6 @@ struct _MMDeviceClass {
|
||||
GObjectClass parent;
|
||||
|
||||
/* signals */
|
||||
void (* port_grabbed) (MMDevice *self,
|
||||
MMKernelDevice *port);
|
||||
void (* port_released) (MMDevice *self,
|
||||
MMKernelDevice *port);
|
||||
};
|
||||
@@ -69,7 +66,7 @@ MMDevice *mm_device_new (const gchar *uid,
|
||||
gboolean virtual,
|
||||
GDBusObjectManagerServer *object_manager);
|
||||
|
||||
void mm_device_grab_port (MMDevice *self,
|
||||
gboolean mm_device_grab_port (MMDevice *self,
|
||||
MMKernelDevice *kernel_port);
|
||||
gboolean mm_device_owns_port (MMDevice *self,
|
||||
MMKernelDevice *kernel_port);
|
||||
@@ -96,7 +93,6 @@ gboolean mm_device_inhibit_finish (MMDevice *self,
|
||||
gboolean mm_device_uninhibit (MMDevice *self,
|
||||
GError **error);
|
||||
|
||||
|
||||
const gchar *mm_device_get_uid (MMDevice *self);
|
||||
const gchar *mm_device_get_physdev (MMDevice *self);
|
||||
const gchar **mm_device_get_drivers (MMDevice *self);
|
||||
@@ -109,14 +105,16 @@ GObject *mm_device_peek_plugin (MMDevice *self);
|
||||
GObject *mm_device_get_plugin (MMDevice *self);
|
||||
MMBaseModem *mm_device_peek_modem (MMDevice *self);
|
||||
MMBaseModem *mm_device_get_modem (MMDevice *self);
|
||||
GObject *mm_device_peek_port_probe (MMDevice *self,
|
||||
MMKernelDevice *kernel_port);
|
||||
GObject *mm_device_get_port_probe (MMDevice *self,
|
||||
MMKernelDevice *kernel_port);
|
||||
GList *mm_device_peek_port_probe_list (MMDevice *self);
|
||||
gboolean mm_device_get_hotplugged (MMDevice *self);
|
||||
gboolean mm_device_get_inhibited (MMDevice *self);
|
||||
|
||||
GObject *mm_device_peek_port_probe (MMDevice *self,
|
||||
MMKernelDevice *kernel_port);
|
||||
GObject *mm_device_get_port_probe (MMDevice *self,
|
||||
MMKernelDevice *kernel_port);
|
||||
GList *mm_device_peek_port_probe_list (MMDevice *self);
|
||||
void mm_device_reset_port_probe_list (MMDevice *self);
|
||||
|
||||
/* For testing purposes */
|
||||
void mm_device_virtual_grab_ports (MMDevice *self,
|
||||
const gchar **ports);
|
||||
|
||||
+59
-42
@@ -784,10 +784,9 @@ struct _DeviceContext {
|
||||
* is reset to 0. */
|
||||
guint extra_probing_time_id;
|
||||
|
||||
/* Signal connection ids for the grabbed/released signals from the device.
|
||||
* These are the signals that will give us notifications of what ports are
|
||||
* available (or suddenly unavailable) in the device. */
|
||||
gulong grabbed_id;
|
||||
/* Signal connection ids for the released signal from the device. This is a
|
||||
* signal that will give us notifications of ports suddenly unavailable in
|
||||
* the device. */
|
||||
gulong released_id;
|
||||
|
||||
/* Port support check contexts being run */
|
||||
@@ -800,7 +799,6 @@ device_context_unref (DeviceContext *device_context)
|
||||
if (g_atomic_int_dec_and_test (&device_context->ref_count)) {
|
||||
/* When the last reference is gone there must be no source scheduled and no
|
||||
* pending port tasks. */
|
||||
g_assert (!device_context->grabbed_id);
|
||||
g_assert (!device_context->released_id);
|
||||
g_assert (!device_context->min_wait_time_id);
|
||||
g_assert (!device_context->min_probing_time_id);
|
||||
@@ -898,18 +896,13 @@ device_context_complete (DeviceContext *device_context)
|
||||
|
||||
/* Steal the task from the context */
|
||||
g_assert (device_context->task);
|
||||
task = device_context->task;
|
||||
device_context->task = NULL;
|
||||
task = g_steal_pointer (&device_context->task);
|
||||
|
||||
/* Log about the time required to complete the checks */
|
||||
mm_obj_dbg (self, "task %s: finished in '%lf' seconds",
|
||||
device_context->name, g_timer_elapsed (device_context->timer, NULL));
|
||||
|
||||
/* Remove signal handlers */
|
||||
if (device_context->grabbed_id) {
|
||||
g_signal_handler_disconnect (device_context->device, device_context->grabbed_id);
|
||||
device_context->grabbed_id = 0;
|
||||
}
|
||||
if (device_context->released_id) {
|
||||
g_signal_handler_disconnect (device_context->device, device_context->released_id);
|
||||
device_context->released_id = 0;
|
||||
@@ -1276,16 +1269,13 @@ device_context_port_released (DeviceContext *device_context,
|
||||
}
|
||||
|
||||
static void
|
||||
device_context_port_grabbed (DeviceContext *device_context,
|
||||
MMKernelDevice *port)
|
||||
device_context_port_added (MMPluginManager *self,
|
||||
DeviceContext *device_context,
|
||||
MMKernelDevice *port)
|
||||
{
|
||||
MMPluginManager *self;
|
||||
PortContext *port_context;
|
||||
PortContext *port_context;
|
||||
|
||||
/* Recover plugin manager */
|
||||
self = MM_PLUGIN_MANAGER (device_context->self);
|
||||
|
||||
mm_obj_dbg (self, "task %s: port grabbed: %s",
|
||||
mm_obj_dbg (self, "task %s: port added: %s",
|
||||
device_context->name, mm_kernel_device_get_name (port));
|
||||
|
||||
/* Ignore if for any reason we still have it in the running list */
|
||||
@@ -1311,7 +1301,7 @@ device_context_port_grabbed (DeviceContext *device_context,
|
||||
(GSourceFunc) device_context_extra_probing_time_elapsed,
|
||||
device_context);
|
||||
|
||||
/* Setup a new port context for the newly grabbed port */
|
||||
/* Setup a new port context for the newly added port */
|
||||
port_context = port_context_new (self,
|
||||
device_context->name,
|
||||
device_context->device,
|
||||
@@ -1332,7 +1322,7 @@ device_context_port_grabbed (DeviceContext *device_context,
|
||||
/* Store the port reference in the list within the device */
|
||||
device_context->port_contexts = g_list_prepend (device_context->port_contexts, port_context) ;
|
||||
|
||||
/* If the port has been grabbed after the min wait timeout expired, launch
|
||||
/* If the port has been added after the min wait timeout expired, launch
|
||||
* probing directly */
|
||||
device_context_run_port_context (device_context, port_context);
|
||||
}
|
||||
@@ -1394,17 +1384,12 @@ device_context_run (MMPluginManager *self,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert (!device_context->task);
|
||||
g_assert (!device_context->grabbed_id);
|
||||
g_assert (!device_context->released_id);
|
||||
g_assert (!device_context->min_wait_time_id);
|
||||
g_assert (!device_context->min_probing_time_id);
|
||||
g_assert (!device_context->extra_probing_time_id);
|
||||
|
||||
/* Connect to device port grabbed/released notifications from the device */
|
||||
device_context->grabbed_id = g_signal_connect_swapped (device_context->device,
|
||||
MM_DEVICE_PORT_GRABBED,
|
||||
G_CALLBACK (device_context_port_grabbed),
|
||||
device_context);
|
||||
/* Connect to device port released notifications from the device */
|
||||
device_context->released_id = g_signal_connect_swapped (device_context->device,
|
||||
MM_DEVICE_PORT_RELEASED,
|
||||
G_CALLBACK (device_context_port_released),
|
||||
@@ -1507,21 +1492,6 @@ plugin_manager_peek_device_context (MMPluginManager *self,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_plugin_manager_device_support_check_cancel (MMPluginManager *self,
|
||||
MMDevice *device)
|
||||
{
|
||||
DeviceContext *device_context;
|
||||
|
||||
/* If the device context isn't found, ignore the cancellation request. */
|
||||
device_context = plugin_manager_peek_device_context (self, device);
|
||||
if (!device_context)
|
||||
return FALSE;
|
||||
|
||||
/* Request cancellation, will be completed asynchronously */
|
||||
return device_context_cancel (device_context);
|
||||
}
|
||||
|
||||
static void
|
||||
device_context_run_ready (MMPluginManager *self,
|
||||
GAsyncResult *res,
|
||||
@@ -1598,6 +1568,53 @@ mm_plugin_manager_device_support_check (MMPluginManager *self,
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Cancel the ongoing device support check, if any */
|
||||
|
||||
gboolean
|
||||
mm_plugin_manager_device_support_check_cancel (MMPluginManager *self,
|
||||
MMDevice *device)
|
||||
{
|
||||
DeviceContext *device_context;
|
||||
|
||||
/* If the device context isn't found, ignore the cancellation request. */
|
||||
device_context = plugin_manager_peek_device_context (self, device);
|
||||
if (!device_context)
|
||||
return FALSE;
|
||||
|
||||
/* Request cancellation, will be completed asynchronously */
|
||||
return device_context_cancel (device_context);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Ask if there is an ongoing device support check */
|
||||
|
||||
gboolean
|
||||
mm_plugin_manager_device_support_check_ongoing (MMPluginManager *self,
|
||||
MMDevice *device)
|
||||
{
|
||||
return !!plugin_manager_peek_device_context (self, device);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Report a new port to the ongoing device support check */
|
||||
|
||||
gboolean
|
||||
mm_plugin_manager_device_support_check_add_port (MMPluginManager *self,
|
||||
MMDevice *device,
|
||||
MMKernelDevice *port)
|
||||
{
|
||||
DeviceContext *device_context;
|
||||
|
||||
device_context = plugin_manager_peek_device_context (self, device);
|
||||
if (device_context) {
|
||||
device_context_port_added (self, device_context, port);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Look for plugin */
|
||||
|
||||
|
||||
@@ -67,6 +67,14 @@ gboolean mm_plugin_manager_device_support_check_cancel (MMPluginManager
|
||||
MMPlugin * mm_plugin_manager_device_support_check_finish (MMPluginManager *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
gboolean mm_plugin_manager_device_support_check_ongoing (MMPluginManager *self,
|
||||
MMDevice *device);
|
||||
|
||||
gboolean mm_plugin_manager_device_support_check_add_port (MMPluginManager *self,
|
||||
MMDevice *device,
|
||||
MMKernelDevice *port);
|
||||
|
||||
MMPlugin *mm_plugin_manager_peek_plugin (MMPluginManager *self,
|
||||
const gchar *plugin_name);
|
||||
const gchar **mm_plugin_manager_get_subsystems (MMPluginManager *self);
|
||||
|
||||
+26
-9
@@ -86,6 +86,15 @@ struct _MMPortProbePrivate {
|
||||
MMDevice *device;
|
||||
MMKernelDevice *port;
|
||||
|
||||
/* From udev tags */
|
||||
gboolean is_ignored;
|
||||
gboolean is_gps;
|
||||
gboolean is_audio;
|
||||
gboolean maybe_at;
|
||||
gboolean maybe_qcdm;
|
||||
gboolean maybe_qmi;
|
||||
gboolean maybe_mbim;
|
||||
|
||||
/* Probing results */
|
||||
guint32 flags;
|
||||
gboolean is_at;
|
||||
@@ -97,19 +106,27 @@ struct _MMPortProbePrivate {
|
||||
gboolean is_qmi;
|
||||
gboolean is_mbim;
|
||||
|
||||
/* From udev tags */
|
||||
gboolean is_ignored;
|
||||
gboolean is_gps;
|
||||
gboolean is_audio;
|
||||
gboolean maybe_at;
|
||||
gboolean maybe_qcdm;
|
||||
gboolean maybe_qmi;
|
||||
gboolean maybe_mbim;
|
||||
|
||||
/* Current probing task. Only one can be available at a time */
|
||||
GTask *task;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
mm_port_probe_reset (MMPortProbe *self)
|
||||
{
|
||||
g_assert (!self->priv->task);
|
||||
self->priv->flags = 0;
|
||||
self->priv->is_at = FALSE;
|
||||
self->priv->is_qcdm = FALSE;
|
||||
g_clear_pointer (&self->priv->vendor, g_free);
|
||||
g_clear_pointer (&self->priv->product, g_free);
|
||||
self->priv->is_icera = FALSE;
|
||||
self->priv->is_xmm = FALSE;
|
||||
self->priv->is_qmi = FALSE;
|
||||
self->priv->is_mbim = FALSE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Probe task completions.
|
||||
* Always make sure that the stored task is NULL when the task is completed.
|
||||
|
||||
+3
-2
@@ -81,8 +81,9 @@ typedef gboolean (* MMPortProbeAtCustomInitFinish) (MMPortProbe *probe,
|
||||
GType mm_port_probe_get_type (void);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortProbe, g_object_unref)
|
||||
|
||||
MMPortProbe *mm_port_probe_new (MMDevice *device,
|
||||
MMKernelDevice *port);
|
||||
MMPortProbe *mm_port_probe_new (MMDevice *device,
|
||||
MMKernelDevice *port);
|
||||
void mm_port_probe_reset (MMPortProbe *self);
|
||||
|
||||
MMDevice *mm_port_probe_peek_device (MMPortProbe *self);
|
||||
MMDevice *mm_port_probe_get_device (MMPortProbe *self);
|
||||
|
||||
Reference in New Issue
Block a user