diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2021-10-17 23:58:30 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2021-10-19 08:27:23 +0000 |
commit | d3b41f0b74af6b6ccfc845d7c565542ed240d773 (patch) | |
tree | c40b5b100b7287b77484d11e1be70b61a1a1bc79 | |
parent | c091860618b3150fc6bc4b24527408234a2f00ad (diff) |
broadband-modem-mbim: early complete successful mode changes
When changing the allowed modes using the "Register State Set"
request, the response would arrive once we have been registered in the
network. This is obviously not ideal, as we just want to know if the
mode preference was changed, we don't care if we're registered or not.
Instead of waiting for the response to arrive or to timeout, we now
also process incoming indications that arrive during the wait time,
and if any of them shows the preferred modes to be the same ones as we
just requested, we complete the operation right away.
-rw-r--r-- | src/mm-broadband-modem-mbim.c | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c index bb804a9d..b9efb97c 100644 --- a/src/mm-broadband-modem-mbim.c +++ b/src/mm-broadband-modem-mbim.c @@ -137,6 +137,7 @@ struct _MMBroadbandModemMbimPrivate { gchar *current_operator_name; gchar *requested_operator_id; MbimDataClass requested_data_class; /* 0 for defaults/auto */ + GTask *pending_allowed_modes_action; /* USSD helpers */ GTask *pending_ussd_action; @@ -1147,17 +1148,61 @@ modem_set_current_modes_finish (MMIfaceModem *self, } static void +complete_pending_allowed_modes_action (MMBroadbandModemMbim *self, + MbimDataClass preferred_data_classes) +{ + MbimDataClass requested_data_classes; + MMModemMode preferred_modes; + MMModemMode requested_modes; + + if (!self->priv->pending_allowed_modes_action) + return; + + requested_data_classes = (MbimDataClass) GPOINTER_TO_UINT (g_task_get_task_data (self->priv->pending_allowed_modes_action)); + requested_modes = mm_modem_mode_from_mbim_data_class (requested_data_classes); + preferred_modes = mm_modem_mode_from_mbim_data_class (preferred_data_classes); + + /* only early complete on success, as we don't know if they're going to be + * intermediate indications emitted before the preference change is valid */ + if (requested_modes == preferred_modes) { + GTask *task; + + task = g_steal_pointer (&self->priv->pending_allowed_modes_action); + g_task_return_boolean (task, TRUE); + g_object_unref (task); + } +} + +static void register_state_current_modes_set_ready (MbimDevice *device, GAsyncResult *res, GTask *task) { g_autoptr(MbimMessage) response = NULL; + MMBroadbandModemMbim *self; GError *error = NULL; MbimDataClass preferred_data_classes; MMModemMode preferred_modes; MbimDataClass requested_data_classes; MMModemMode requested_modes; + self = g_task_get_source_object (task); + requested_data_classes = (MbimDataClass) GPOINTER_TO_UINT (g_task_get_task_data (task)); + + /* If the task is still in the private info, it means it wasn't either + * cancelled or completed, so we just unref that reference and go on + * with out response processing. But if the task is no longer in the + * private info (or if there's a different task), then it means we're + * either cancelled (by some new incoming user request) or otherwise + * successfully completed (if completed via a Register State indication). + * In both those cases, just unref the incoming task and go on. */ + if (self->priv->pending_allowed_modes_action != task) { + g_assert (g_task_get_completed (task)); + g_object_unref (task); + return; + } + g_clear_object (&self->priv->pending_allowed_modes_action); + response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) || @@ -1179,7 +1224,6 @@ register_state_current_modes_set_ready (MbimDevice *device, return; } - requested_data_classes = (MbimDataClass) GPOINTER_TO_UINT (g_task_get_task_data (task)); requested_modes = mm_modem_mode_from_mbim_data_class (requested_data_classes); preferred_modes = mm_modem_mode_from_mbim_data_class (preferred_data_classes); @@ -1231,14 +1275,16 @@ modem_set_current_modes (MMIfaceModem *_self, GAsyncReadyCallback callback, gpointer user_data) { - MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); - GTask *task; - MbimDevice *device; + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); + GTask *task; + MbimDevice *device; + g_autoptr(GCancellable) cancellable = NULL; if (!peek_device (self, &device, callback, user_data)) return; - task = g_task_new (self, NULL, callback, user_data); + cancellable = g_cancellable_new (); + task = g_task_new (self, cancellable, callback, user_data); #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED if (self->priv->qmi_capability_and_mode_switching) { @@ -1261,7 +1307,20 @@ modem_set_current_modes (MMIfaceModem *_self, self->priv->requested_data_class = mm_mbim_data_class_from_modem_mode (allowed, mm_iface_modem_is_3gpp (_self), mm_iface_modem_is_cdma (_self)); + + /* Store the ongoing allowed modes action, so that we can finish the + * operation early via indications, instead of waiting for the modem + * to be registered on the requested access technologies */ g_task_set_task_data (task, GUINT_TO_POINTER (self->priv->requested_data_class), NULL); + if (self->priv->pending_allowed_modes_action) { + /* cancel the task and clear this reference; the _set_ready() + * will take care of completing the task */ + g_cancellable_cancel (g_task_get_cancellable (self->priv->pending_allowed_modes_action)); + g_task_return_error_if_cancelled (self->priv->pending_allowed_modes_action); + g_clear_object (&self->priv->pending_allowed_modes_action); + } + self->priv->pending_allowed_modes_action = g_object_ref (task); + /* use the last requested operator id to determine whether the * registration should be manual or automatic */ message = mbim_message_register_state_set_new ( @@ -3606,6 +3665,7 @@ basic_connect_notification_register_state (MMBroadbandModemMbim *self, MbimDataClass available_data_classes; gchar *provider_id; gchar *provider_name; + MbimDataClass preferred_data_classes = 0; if (mbim_device_check_ms_mbimex_version (device, 2, 0)) { if (!mbim_message_ms_basic_connect_v2_register_state_notification_parse ( @@ -3619,7 +3679,7 @@ basic_connect_notification_register_state (MMBroadbandModemMbim *self, &provider_name, NULL, /* roaming_text */ NULL, /* registration_flag */ - NULL, /* preferred_data_classes */ + &preferred_data_classes, &error)) { mm_obj_warn (self, "failed processing MBIMEx v2.0 register state indication: %s", error->message); return; @@ -3649,6 +3709,9 @@ basic_connect_notification_register_state (MMBroadbandModemMbim *self, available_data_classes, provider_id, provider_name); + + if (preferred_data_classes) + complete_pending_allowed_modes_action (self, preferred_data_classes); } typedef struct { |