aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem-qmi.c272
1 files changed, 245 insertions, 27 deletions
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 990ffce4..71e0cf75 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -12,7 +12,7 @@
*
* Copyright (C) 2012 Google Inc.
* Copyright (C) 2014 Aleksander Morgado <aleksander@aleksander.es>
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <config.h>
@@ -161,6 +161,13 @@ struct _MMBroadbandModemQmiPrivate {
/* For notifying when the qmi-proxy connection is dead */
guint qmi_device_removed_id;
+
+ /* Power Indication Helper */
+ guint power_event_report_indication_id;
+
+ /* Power Set Operating Mode Helper */
+ GTask *set_operating_mode_task;
+ guint set_operating_timeout_id;
};
/*****************************************************************************/
@@ -1699,6 +1706,181 @@ load_signal_quality (MMIfaceModem *self,
}
/*****************************************************************************/
+/* Power Indication Registration */
+
+static void
+dms_set_operating_mode (MMBroadbandModemQmi *self);
+
+static void
+modem_power_indication_deregister (MMBroadbandModemQmi *self)
+{
+ QmiMessageDmsSetEventReportInput *input = NULL;
+ QmiClient *client = NULL;
+
+ g_assert (self->priv->power_event_report_indication_id != 0);
+ g_signal_handler_disconnect (QMI_CLIENT_DMS (client),
+ self->priv->power_event_report_indication_id);
+ self->priv->power_event_report_indication_id = 0;
+
+ client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_DMS,
+ MM_PORT_QMI_FLAG_DEFAULT,
+ NULL);
+ if (!client) {
+ return;
+ }
+
+ input = qmi_message_dms_set_event_report_input_new ();
+ qmi_message_dms_set_event_report_input_set_operating_mode_reporting (input, FALSE, NULL);
+ mm_obj_dbg (self, "Power indication deregistration request is sent");
+ qmi_client_dms_set_event_report (
+ QMI_CLIENT_DMS (client),
+ input,
+ 5,
+ NULL,
+ NULL,
+ NULL);
+ qmi_message_dms_set_event_report_input_unref (input);
+}
+
+static void
+dms_set_operating_mode_complete (MMBroadbandModemQmi *self,
+ GError *error)
+{
+ GTask *task;
+
+ task = g_steal_pointer (&(self->priv->set_operating_mode_task));
+
+ if (self->priv->set_operating_timeout_id) {
+ g_source_remove (self->priv->set_operating_timeout_id);
+ self->priv->set_operating_timeout_id = 0;
+ }
+ if (self->priv->power_event_report_indication_id) {
+ modem_power_indication_deregister (self);
+ }
+ g_assert (task != NULL);
+ if (error) {
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+}
+
+static void
+dms_set_operating_mode_timeout_cb (MMBroadbandModemQmi *self)
+{
+ GError *error = NULL;
+
+ error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Operation timed out. Did not get any indication");
+ dms_set_operating_mode_complete (self, error);
+ g_object_unref (self);
+}
+
+static void
+power_event_report_indication_cb (QmiClientDms *client,
+ QmiIndicationDmsEventReportOutput *output,
+ MMBroadbandModemQmi *self)
+{
+ QmiDmsOperatingMode state;
+ GTask *task;
+ GError *error = NULL;
+ QmiDmsOperatingMode mode;
+
+ mm_obj_dbg (self, "Power indication received");
+
+ 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");
+ dms_set_operating_mode_complete (self, error);
+ g_object_unref (self);
+ return;
+ }
+ mm_obj_dbg (self, "Power state update: '%s'",
+ qmi_dms_operating_mode_get_string (state));
+ task = self->priv->set_operating_mode_task;
+ mode = GPOINTER_TO_UINT (g_task_get_task_data (task));
+ if (mode == state) {
+ mm_obj_dbg (self, "Requested mode and mode received by indication matched");
+ dms_set_operating_mode_complete (self, NULL);
+ g_object_unref (self);
+ return;
+ }
+ error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Requested mode and mode received by indication did not match");
+ dms_set_operating_mode_complete (self, error);
+ g_object_unref (self);
+}
+
+static void
+power_indication_activation_callback_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ MMBroadbandModemQmi *self)
+{
+ QmiMessageDmsSetEventReportOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_dms_set_event_report_finish (client, res, &error);
+ if (!output) {
+ g_prefix_error (&error, "Power indication activation qmi operation failed");
+ dms_set_operating_mode_complete (self, error);
+ g_object_unref (self);
+ return;
+ }
+ if (!qmi_message_dms_set_event_report_output_get_result (output, &error)) {
+ qmi_message_dms_set_event_report_output_unref (output);
+ g_prefix_error (&error, "Power indication failed: couldn't set event report");
+ dms_set_operating_mode_complete (self, error);
+ g_object_unref (self);
+ return;
+ }
+ qmi_message_dms_set_event_report_output_unref (output);
+ g_assert (self->priv->power_event_report_indication_id == 0);
+ self->priv->power_event_report_indication_id =
+ g_signal_connect (client,
+ "event-report",
+ G_CALLBACK (power_event_report_indication_cb),
+ g_object_ref (self));
+ g_assert (self->priv->set_operating_mode_task != NULL);
+ mm_obj_dbg (self, "Power operation is pending");
+ dms_set_operating_mode (self);
+ g_object_unref (self);
+}
+
+static void
+modem_power_indication_register (MMBroadbandModemQmi *self)
+{
+ QmiMessageDmsSetEventReportInput *input = NULL;
+ QmiClient *client = NULL;
+ GError *error = NULL;
+
+ client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_DMS,
+ MM_PORT_QMI_FLAG_DEFAULT,
+ &error);
+
+ if (!client) {
+ dms_set_operating_mode_complete (self, error);
+ return;
+ }
+ input = qmi_message_dms_set_event_report_input_new ();
+ qmi_message_dms_set_event_report_input_set_operating_mode_reporting (input, TRUE, NULL);
+ mm_obj_dbg (self, "Power indication registration request is sent");
+ qmi_client_dms_set_event_report (
+ QMI_CLIENT_DMS (client),
+ input,
+ 5,
+ NULL,
+ (GAsyncReadyCallback)power_indication_activation_callback_ready,
+ g_object_ref (self));
+ qmi_message_dms_set_event_report_input_unref (input);
+}
+
+/*****************************************************************************/
/* Powering up the modem (Modem interface) */
static gboolean
@@ -1712,14 +1894,19 @@ modem_power_up_down_off_finish (MMIfaceModem *self,
static void
dms_set_operating_mode_ready (QmiClientDms *client,
GAsyncResult *res,
- GTask *task)
+ MMBroadbandModemQmi *self)
{
- MMBroadbandModemQmi *self;
- QmiDmsOperatingMode mode;
- GError *error = NULL;
- g_autoptr(QmiMessageDmsSetOperatingModeOutput) output = NULL;
+ GTask *task;
+ QmiDmsOperatingMode mode;
+ GError *error = NULL;
+ g_autoptr (QmiMessageDmsSetOperatingModeOutput) output = NULL;
- self = g_task_get_source_object (task);
+ task = self->priv->set_operating_mode_task;
+ if (task == NULL) {
+ mm_obj_dbg (self, "Indication received before response. Task returned.");
+ g_object_unref (self);
+ return;
+ }
mode = GPOINTER_TO_UINT (g_task_get_task_data (task));
output = qmi_client_dms_set_operating_mode_finish (client, res, &error);
@@ -1751,31 +1938,33 @@ dms_set_operating_mode_ready (QmiClientDms *client,
}
}
- if (error)
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
+ if (error) {
+ dms_set_operating_mode_complete (self, error);
+ } else {
+ mm_obj_dbg (self, "Waiting for power indication to send success for the task");
+ }
+ g_object_unref (self);
}
static void
-common_power_up_down_off (MMIfaceModem *self,
- QmiDmsOperatingMode mode,
- GAsyncReadyCallback callback,
- gpointer user_data)
+dms_set_operating_mode (MMBroadbandModemQmi *self)
{
- GTask *task;
- QmiClient *client = NULL;
- g_autoptr(QmiMessageDmsSetOperatingModeInput) input = NULL;
+ QmiClient *client = NULL;
+ GError *error = NULL;
+ GTask *task = NULL;
+ QmiDmsOperatingMode mode;
+ g_autoptr (QmiMessageDmsSetOperatingModeInput) input = NULL;
- if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
- QMI_SERVICE_DMS, &client,
- callback, user_data))
+ task = self->priv->set_operating_mode_task;
+ mode = GPOINTER_TO_UINT (g_task_get_task_data(task));
+ client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_DMS,
+ MM_PORT_QMI_FLAG_DEFAULT,
+ &error);
+ if (!client) {
+ dms_set_operating_mode_complete (self, error);
return;
-
- task = g_task_new (self, NULL, callback, user_data);
- g_task_set_task_data (task, GUINT_TO_POINTER (mode), NULL);
-
+ }
input = qmi_message_dms_set_operating_mode_input_new ();
qmi_message_dms_set_operating_mode_input_set_mode (input, mode, NULL);
qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (client),
@@ -1783,7 +1972,36 @@ common_power_up_down_off (MMIfaceModem *self,
20,
NULL,
(GAsyncReadyCallback)dms_set_operating_mode_ready,
- task);
+ g_object_ref (self));
+ mm_obj_dbg (self, "Starting timeout for indication receiving for 10 seconds");
+ self->priv->set_operating_timeout_id = g_timeout_add_seconds (10,
+ (GSourceFunc) dms_set_operating_mode_timeout_cb,
+ g_object_ref (self));
+}
+
+static void
+common_power_up_down_off (MMIfaceModem *_self,
+ QmiDmsOperatingMode mode,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ GError *error = NULL;
+ MMBroadbandModemQmi *self = NULL;
+
+ self = MM_BROADBAND_MODEM_QMI (_self);
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, GUINT_TO_POINTER (mode), NULL);
+
+ if (self->priv->set_operating_mode_task) {
+ error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS, "Another Operation in Progress");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ self->priv->set_operating_mode_task = task;
+ g_assert (self->priv->set_operating_mode_task != NULL);
+ modem_power_indication_register (self);
}
static void