diff options
author | Aleksander Morgado <aleksandermj@chromium.org> | 2024-03-06 13:47:55 +0000 |
---|---|---|
committer | Aleksander Morgado <aleksandermj@chromium.org> | 2024-03-12 10:15:59 +0000 |
commit | bd255849dcdbcaa3280033b0974a6a5e0473566e (patch) | |
tree | 128d517534eb046d521d471233ffd3c4b390d285 /src/mm-plugin-manager.c | |
parent | 07f1f5864204dfdf455067def863fcd20c8c6a26 (diff) |
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.
Diffstat (limited to 'src/mm-plugin-manager.c')
-rw-r--r-- | src/mm-plugin-manager.c | 101 |
1 files changed, 59 insertions, 42 deletions
diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c index c2438664..0179e5d0 100644 --- a/src/mm-plugin-manager.c +++ b/src/mm-plugin-manager.c @@ -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; - - /* Recover plugin manager */ - self = MM_PLUGIN_MANAGER (device_context->self); + PortContext *port_context; - 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, @@ -1599,6 +1569,53 @@ mm_plugin_manager_device_support_check (MMPluginManager *self, } /*****************************************************************************/ +/* 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 */ MMPlugin * |