aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-broadband-modem-qmi.c242
1 files changed, 144 insertions, 98 deletions
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index a040d60a..025248bd 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -1984,13 +1984,17 @@ get_cell_info (MMIfaceModem *self,
typedef struct {
QmiDmsOperatingMode mode;
QmiClientDms *client;
+ gboolean event_report_set;
guint indication_id;
guint timeout_id;
+ gboolean reload;
+ GError *saved_error;
} SetOperatingModeContext;
static void
set_operating_mode_context_free (SetOperatingModeContext *ctx)
{
+ g_assert (!ctx->saved_error);
g_assert (ctx->indication_id == 0);
g_assert (ctx->timeout_id == 0);
g_clear_object (&ctx->client);
@@ -2006,108 +2010,152 @@ modem_power_up_down_off_finish (MMIfaceModem *self,
}
static void
-set_operating_mode_context_reset (SetOperatingModeContext *ctx)
+set_operating_mode_done (MMBroadbandModemQmi *self)
{
- if (ctx->timeout_id) {
- g_source_remove (ctx->timeout_id);
- ctx->timeout_id = 0;
- }
-
- if (ctx->indication_id) {
- g_autoptr(QmiMessageDmsSetEventReportInput) input = NULL;
+ GTask *task;
+ SetOperatingModeContext *ctx;
- g_signal_handler_disconnect (ctx->client, ctx->indication_id);
- ctx->indication_id = 0;
+ g_assert (self->priv->set_operating_mode_task);
+ task = g_steal_pointer (&self->priv->set_operating_mode_task);
+ ctx = g_task_get_task_data (task);
- input = qmi_message_dms_set_event_report_input_new ();
- qmi_message_dms_set_event_report_input_set_operating_mode_reporting (input, FALSE, NULL);
- qmi_client_dms_set_event_report (ctx->client, input, 5, NULL, NULL, NULL);
- }
+ if (ctx->saved_error)
+ g_task_return_error (task, g_steal_pointer (&ctx->saved_error));
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
}
static void
-dms_check_current_operating_mode_ready (QmiClientDms *client,
- GAsyncResult *res,
- GTask *task)
+dms_reload_current_operating_mode_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ MMBroadbandModemQmi *self) /* full reference */
{
- QmiMessageDmsGetOperatingModeOutput *output = NULL;
- GError *error = NULL;
- SetOperatingModeContext *ctx;
+ g_autoptr(QmiMessageDmsGetOperatingModeOutput) output = NULL;
+ g_autoptr(GError) error = NULL;
+ SetOperatingModeContext *ctx;
- ctx = g_task_get_task_data (task);
+ g_assert (self->priv->set_operating_mode_task);
+ ctx = g_task_get_task_data (self->priv->set_operating_mode_task);
+
+ /* Reloading the current operating mode is only expected if the operation is
+ * failed for some other reason */
+ g_assert (ctx->saved_error);
output = qmi_client_dms_get_operating_mode_finish (client, res, &error);
- if (!output) {
- g_prefix_error (&error, "QMI operation failed: ");
- g_task_return_error (task, error);
- } else if (!qmi_message_dms_get_operating_mode_output_get_result (output, &error)) {
- g_prefix_error (&error, "Couldn't get operating mode: ");
- g_task_return_error (task, error);
+ if (!output || !qmi_message_dms_get_operating_mode_output_get_result (output, &error)) {
+ mm_obj_warn (self, "couldn't reload current operating mode: %s", error->message);
} else {
QmiDmsOperatingMode mode = QMI_DMS_OPERATING_MODE_UNKNOWN;
qmi_message_dms_get_operating_mode_output_get_mode (output, &mode, NULL);
- if (mode == ctx->mode)
- g_task_return_boolean (task, TRUE);
- else
- g_task_return_new_error (task,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Requested mode (%s) and mode received (%s) did not match",
- qmi_dms_operating_mode_get_string (ctx->mode),
- qmi_dms_operating_mode_get_string (mode));
+ if (mode != ctx->mode) {
+ g_prefix_error (&ctx->saved_error,
+ "Requested (%s) and reloaded (%s) modes did not match: ",
+ qmi_dms_operating_mode_get_string (ctx->mode),
+ qmi_dms_operating_mode_get_string (mode));
+ } else {
+ /* Reloaded mode is the one we requested! we can cleanup the saved error
+ * as the operation did really not fail */
+ mm_obj_info (self, "power update operation successful even after error");
+ g_clear_error (&ctx->saved_error);
+ }
}
- if (output)
- qmi_message_dms_get_operating_mode_output_unref (output);
-
- g_object_unref (task);
+ set_operating_mode_done (self);
+ g_object_unref (self);
}
-static gboolean
-dms_set_operating_mode_timeout_cb (MMBroadbandModemQmi *self)
+static void
+set_operating_mode_reload (MMBroadbandModemQmi *self)
{
- GTask *task;
SetOperatingModeContext *ctx;
g_assert (self->priv->set_operating_mode_task);
- task = g_steal_pointer (&self->priv->set_operating_mode_task);
- ctx = g_task_get_task_data (task);
+ ctx = g_task_get_task_data (self->priv->set_operating_mode_task);
+ if (ctx->reload) {
+ mm_obj_dbg (self, "reload current device operating mode...");
+ qmi_client_dms_get_operating_mode (ctx->client,
+ NULL,
+ 5,
+ NULL,
+ (GAsyncReadyCallback)dms_reload_current_operating_mode_ready,
+ g_object_ref (self));
+ return;
+ }
- mm_obj_warn (self, "Power update operation timed out");
+ set_operating_mode_done (self);
+}
- set_operating_mode_context_reset (ctx);
+static void
+dms_set_event_report_operating_mode_deactivate_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ MMBroadbandModemQmi *self) /* full reference */
+{
+ g_autoptr(QmiMessageDmsSetEventReportOutput) output = NULL;
+ g_autoptr(GError) error = NULL;
- mm_obj_dbg (self, "check current device operating mode...");
- qmi_client_dms_get_operating_mode (ctx->client,
- NULL,
- 5,
- NULL,
- (GAsyncReadyCallback)dms_check_current_operating_mode_ready,
- task);
+ g_assert (self->priv->set_operating_mode_task);
- return G_SOURCE_REMOVE;
+ output = qmi_client_dms_set_event_report_finish (client, res, &error);
+ if (!output || !qmi_message_dms_set_event_report_output_get_result (output, &error))
+ mm_obj_dbg (self, "couldn't deregister for power indications: %s", error->message);
+
+ set_operating_mode_reload (self);
+ g_object_unref (self);
}
static void
-set_operating_mode_complete (MMBroadbandModemQmi *self,
- GError *error)
+set_operating_mode_complete (MMBroadbandModemQmi *self)
{
- GTask *task;
SetOperatingModeContext *ctx;
g_assert (self->priv->set_operating_mode_task);
- task = g_steal_pointer (&self->priv->set_operating_mode_task);
- ctx = g_task_get_task_data (task);
+ ctx = g_task_get_task_data (self->priv->set_operating_mode_task);
- set_operating_mode_context_reset (ctx);
+ if (ctx->timeout_id) {
+ g_source_remove (ctx->timeout_id);
+ ctx->timeout_id = 0;
+ }
- if (error)
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
+ if (ctx->indication_id) {
+ g_signal_handler_disconnect (ctx->client, ctx->indication_id);
+ ctx->indication_id = 0;
+ }
+
+ if (ctx->event_report_set) {
+ g_autoptr(QmiMessageDmsSetEventReportInput) input = NULL;
+
+ input = qmi_message_dms_set_event_report_input_new ();
+ qmi_message_dms_set_event_report_input_set_operating_mode_reporting (input, FALSE, NULL);
+ qmi_client_dms_set_event_report (ctx->client,
+ input,
+ 5,
+ NULL,
+ (GAsyncReadyCallback)dms_set_event_report_operating_mode_deactivate_ready,
+ g_object_ref (self));
+ return;
+ }
+
+ set_operating_mode_reload (self);
+}
+
+static gboolean
+dms_set_operating_mode_timeout_cb (MMBroadbandModemQmi *self)
+{
+ SetOperatingModeContext *ctx;
+
+ g_assert (self->priv->set_operating_mode_task);
+ ctx = g_task_get_task_data (self->priv->set_operating_mode_task);
+
+ /* Save a timeout error, but also request to reload, in case the modem
+ * failed to send the indication even if it did update the power state */
+ ctx->saved_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_TIMEOUT, "Power update operation timed out");
+ ctx->reload = TRUE;
+
+ set_operating_mode_complete (self);
+ return G_SOURCE_REMOVE;
}
static void
@@ -2116,30 +2164,24 @@ power_event_report_indication_cb (QmiClientDms *client,
MMBroadbandModemQmi *self)
{
QmiDmsOperatingMode state;
- GError *error = NULL;
SetOperatingModeContext *ctx;
- if (!qmi_indication_dms_event_report_output_get_operating_mode (output, &state, NULL)) {
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid power indication received");
- set_operating_mode_complete (self, error);
- return;
- }
-
g_assert (self->priv->set_operating_mode_task);
ctx = g_task_get_task_data (self->priv->set_operating_mode_task);
- if (ctx->mode == state) {
+ g_assert (!ctx->saved_error);
+ if (!qmi_indication_dms_event_report_output_get_operating_mode (output, &state, NULL))
+ ctx->saved_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid power indication received");
+ else if (ctx->mode != state)
+ ctx->saved_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Requested (%s) and notified (%s) modes did not match",
+ qmi_dms_operating_mode_get_string (ctx->mode),
+ qmi_dms_operating_mode_get_string (state));
+ else
mm_obj_dbg (self, "Power state successfully updated: '%s'", qmi_dms_operating_mode_get_string (state));
- set_operating_mode_complete (self, NULL);
- return;
- }
- error = g_error_new (MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Requested mode (%s) and mode received (%s) did not match",
- qmi_dms_operating_mode_get_string (ctx->mode),
- qmi_dms_operating_mode_get_string (state));
- set_operating_mode_complete (self, error);
+ set_operating_mode_complete (self);
}
static void
@@ -2185,20 +2227,23 @@ dms_set_operating_mode_ready (QmiClientDms *client,
if (g_error_matches (error, QMI_CORE_ERROR, QMI_CORE_ERROR_UNSUPPORTED)) {
mm_obj_dbg (self, "device doesn't support operating mode setting: ignoring power update");
g_clear_error (&error);
- set_operating_mode_complete (self, NULL);
- } else if (error)
- set_operating_mode_complete (self, error);
- else if (ctx->timeout_id)
+ set_operating_mode_complete (self);
+ } else if (error) {
+ ctx->saved_error = error;
+ set_operating_mode_complete (self);
+ } else if (ctx->event_report_set) {
+ g_assert (ctx->timeout_id);
mm_obj_dbg (self, "operating mode request sent, waiting for power update indication");
- else
- set_operating_mode_complete (self, NULL);
+ } else {
+ mm_obj_dbg (self, "operating mode request finished: no need to wait for indications");
+ set_operating_mode_complete (self);
+ }
g_object_unref (self);
}
static void
-dms_set_operating_mode (MMBroadbandModemQmi *self,
- gboolean supports_power_indications)
+dms_set_operating_mode (MMBroadbandModemQmi *self)
{
g_autoptr (QmiMessageDmsSetOperatingModeInput) input = NULL;
SetOperatingModeContext *ctx;
@@ -2215,7 +2260,7 @@ dms_set_operating_mode (MMBroadbandModemQmi *self,
(GAsyncReadyCallback)dms_set_operating_mode_ready,
g_object_ref (self));
- if (supports_power_indications) {
+ if (ctx->event_report_set) {
mm_obj_dbg (self, "Starting timeout for indication receiving for 10 seconds");
ctx->timeout_id = g_timeout_add_seconds (10,
(GSourceFunc) dms_set_operating_mode_timeout_cb,
@@ -2231,7 +2276,6 @@ dms_set_event_report_operating_mode_activate_ready (QmiClientDms *client,
g_autoptr(QmiMessageDmsSetEventReportOutput) output = NULL;
GError *error = NULL;
SetOperatingModeContext *ctx;
- gboolean supports_power_indications = TRUE;
g_assert (self->priv->set_operating_mode_task);
ctx = g_task_get_task_data (self->priv->set_operating_mode_task);
@@ -2241,17 +2285,20 @@ dms_set_event_report_operating_mode_activate_ready (QmiClientDms *client,
if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_MISSING_ARGUMENT)) {
mm_obj_dbg (self, "device doesn't support power indication registration: ignore it and continue");
g_clear_error (&error);
- supports_power_indications = FALSE;
} else {
g_prefix_error (&error, "Couldn't register for power indications: ");
- set_operating_mode_complete (self, error);
+ ctx->saved_error = error;
+ set_operating_mode_complete (self);
g_object_unref (self);
return;
}
+ } else {
+ mm_obj_dbg (self, "device supports power indications");
+ ctx->event_report_set = TRUE;
}
g_assert (ctx->indication_id == 0);
- if (supports_power_indications) {
+ if (ctx->event_report_set) {
ctx->indication_id = g_signal_connect (client,
"event-report",
G_CALLBACK (power_event_report_indication_cb),
@@ -2259,8 +2306,7 @@ dms_set_event_report_operating_mode_activate_ready (QmiClientDms *client,
mm_obj_dbg (self, "Power operation is pending");
}
- dms_set_operating_mode (self,
- supports_power_indications);
+ dms_set_operating_mode (self);
g_object_unref (self);
}