aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2015-02-07 21:39:00 +0100
committerAleksander Morgado <aleksander@aleksander.es>2015-02-07 21:39:15 +0100
commita83d1c70b1f433bcb9a33b4cb1b5e3032050a104 (patch)
tree2daf0143283a7000da746f2ea112e432789c317b
parentb6f8e5f08de8860b4c54609a3648cb86a04244ea (diff)
broadband-modem-qmi: use 'DMS Set FCC Authentication' if online mode fails
Some new devices, like the Dell DW5770, will return an internal error when trying to bring the power mode to online. We can avoid this by sending the magic "DMS Set FCC Auth" message before retrying. Bumping libqmi version to 1.13.4, which is the one that supports this new message. https://bugzilla.kernel.org/show_bug.cgi?id=92101
-rw-r--r--configure.ac2
-rw-r--r--src/mm-broadband-modem-qmi.c185
2 files changed, 143 insertions, 44 deletions
diff --git a/configure.ac b/configure.ac
index dd9b112b..93bd6b30 100644
--- a/configure.ac
+++ b/configure.ac
@@ -251,7 +251,7 @@ AC_ARG_WITH(qmi, AS_HELP_STRING([--without-qmi], [Build without QMI support]), [
AM_CONDITIONAL(WITH_QMI, test "x$with_qmi" = "xyes")
case $with_qmi in
yes)
- PKG_CHECK_MODULES(QMI, [qmi-glib >= 1.11.1], [have_qmi=yes],[have_qmi=no])
+ PKG_CHECK_MODULES(QMI, [qmi-glib >= 1.13.4], [have_qmi=yes],[have_qmi=no])
if test "x$have_qmi" = "xno"; then
AC_MSG_ERROR([Couldn't find libqmi-glib. Install it, or otherwise configure using --without-qmi to disable QMI support.])
else
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index d43b71a1..c808345d 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -2481,6 +2481,32 @@ load_signal_quality (MMIfaceModem *self,
/*****************************************************************************/
/* Powering up the modem (Modem interface) */
+typedef enum {
+ SET_OPERATING_MODE_STEP_FIRST,
+ SET_OPERATING_MODE_STEP_FCC_AUTH,
+ SET_OPERATING_MODE_STEP_RETRY,
+ SET_OPERATING_MODE_STEP_LAST
+} SetOperatingModeStep;
+
+typedef struct {
+ MMBroadbandModemQmi *self;
+ QmiClientDms *client;
+ GSimpleAsyncResult *result;
+ QmiMessageDmsSetOperatingModeInput *input;
+ SetOperatingModeStep step;
+} SetOperatingModeContext;
+
+static void
+set_operating_mode_context_complete_and_free (SetOperatingModeContext *ctx)
+{
+ g_simple_async_result_complete (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->client);
+ g_object_unref (ctx->self);
+ qmi_message_dms_set_operating_mode_input_unref (ctx->input);
+ g_slice_free (SetOperatingModeContext, ctx);
+}
+
static gboolean
modem_power_up_down_off_finish (MMIfaceModem *self,
GAsyncResult *res,
@@ -2489,38 +2515,125 @@ modem_power_up_down_off_finish (MMIfaceModem *self,
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
+static void set_operating_mode_context_step (SetOperatingModeContext *ctx);
+
+static void
+dms_set_fcc_authentication_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ SetOperatingModeContext *ctx)
+{
+ QmiMessageDmsSetFccAuthenticationOutput *output = NULL;
+ GError *error = NULL;
+
+ output = qmi_client_dms_set_fcc_authentication_finish (client, res, &error);
+ if (!output || !qmi_message_dms_set_fcc_authentication_output_get_result (output, &error)) {
+ /* No hard errors */
+ mm_dbg ("Couldn't set FCC authentication: %s", error->message);
+ g_error_free (error);
+ }
+
+ if (output)
+ qmi_message_dms_set_fcc_authentication_output_unref (output);
+
+ /* Retry Set Operating Mode */
+ ctx->step++;
+ set_operating_mode_context_step (ctx);
+}
+
static void
dms_set_operating_mode_ready (QmiClientDms *client,
GAsyncResult *res,
- GSimpleAsyncResult *simple)
+ SetOperatingModeContext *ctx)
{
QmiMessageDmsSetOperatingModeOutput *output = NULL;
GError *error = NULL;
output = qmi_client_dms_set_operating_mode_finish (client, res, &error);
if (!output) {
- if (g_error_matches (error,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_UNSUPPORTED)) {
+ /* If unsupported, just go out without errors */
+ if (g_error_matches (error, QMI_CORE_ERROR, QMI_CORE_ERROR_UNSUPPORTED)) {
mm_dbg ("Device doesn't support operating mode setting. Ignoring power update.");
- g_simple_async_result_set_op_res_gboolean (simple, TRUE);
g_error_free (error);
- } else {
- g_prefix_error (&error, "QMI operation failed: ");
- g_simple_async_result_take_error (simple, error);
+ ctx->step = SET_OPERATING_MODE_STEP_LAST;
+ set_operating_mode_context_step (ctx);
+ return;
}
- } else if (!qmi_message_dms_set_operating_mode_output_get_result (output, &error)) {
- g_prefix_error (&error, "Couldn't set operating mode: ");
- g_simple_async_result_take_error (simple, error);
- } else {
- g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_simple_async_result_take_error (ctx->result, error);
+ set_operating_mode_context_complete_and_free (ctx);
+ return;
}
- if (output)
+ if (!qmi_message_dms_set_operating_mode_output_get_result (output, &error)) {
+ QmiDmsOperatingMode mode;
+
+ /* Some new devices, like the Dell DW5770, will return an internal error when
+ * trying to bring the power mode to online. We can avoid this by sending the
+ * magic "DMS Set FCC Auth" message before trying. */
+ if (ctx->step == SET_OPERATING_MODE_STEP_FIRST &&
+ qmi_message_dms_set_operating_mode_input_get_mode (ctx->input, &mode, NULL) &&
+ mode == QMI_DMS_OPERATING_MODE_ONLINE &&
+ g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INTERNAL)) {
+ g_error_free (error);
+ /* Go on to FCC auth */
+ ctx->step++;
+ set_operating_mode_context_step (ctx);
+ qmi_message_dms_set_operating_mode_output_unref (output);
+ return;
+ }
+
+ g_prefix_error (&error, "Couldn't set operating mode: ");
+ g_simple_async_result_take_error (ctx->result, error);
qmi_message_dms_set_operating_mode_output_unref (output);
+ set_operating_mode_context_complete_and_free (ctx);
+ return;
+ }
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ /* Good! */
+ ctx->step++;
+ set_operating_mode_context_step (ctx);
+}
+
+static void
+set_operating_mode_context_step (SetOperatingModeContext *ctx)
+{
+ switch (ctx->step) {
+ case SET_OPERATING_MODE_STEP_FIRST:
+ mm_dbg ("Setting device operating mode...");
+ qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (ctx->client),
+ ctx->input,
+ 20,
+ NULL,
+ (GAsyncReadyCallback)dms_set_operating_mode_ready,
+ ctx);
+ return;
+ case SET_OPERATING_MODE_STEP_FCC_AUTH:
+ mm_dbg ("Setting FCC auth...");
+ qmi_client_dms_set_fcc_authentication (QMI_CLIENT_DMS (ctx->client),
+ NULL,
+ 5,
+ NULL,
+ (GAsyncReadyCallback)dms_set_fcc_authentication_ready,
+ ctx);
+ return;
+ case SET_OPERATING_MODE_STEP_RETRY:
+ mm_dbg ("Setting device operating mode (retry)...");
+ qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (ctx->client),
+ ctx->input,
+ 20,
+ NULL,
+ (GAsyncReadyCallback)dms_set_operating_mode_ready,
+ ctx);
+ return;
+ case SET_OPERATING_MODE_STEP_LAST:
+ /* Good! */
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ set_operating_mode_context_complete_and_free (ctx);
+ return;
+ default:
+ g_assert_not_reached ();
+ }
}
static void
@@ -2529,41 +2642,27 @@ common_power_up_down_off (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- QmiMessageDmsSetOperatingModeInput *input;
- GSimpleAsyncResult *result;
+ SetOperatingModeContext *ctx;
QmiClient *client = NULL;
- GError *error = NULL;
if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
QMI_SERVICE_DMS, &client,
callback, user_data))
return;
- result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- common_power_up_down_off);
-
- input = qmi_message_dms_set_operating_mode_input_new ();
- if (!qmi_message_dms_set_operating_mode_input_set_mode (
- input,
- mode,
- &error)) {
- qmi_message_dms_set_operating_mode_input_unref (input);
- g_simple_async_result_take_error (result, error);
- g_simple_async_result_complete_in_idle (result);
- g_object_unref (result);
- return;
- }
+ /* Setup context */
+ ctx = g_slice_new0 (SetOperatingModeContext);
+ ctx->self = g_object_ref (self);
+ ctx->client = g_object_ref (client);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ common_power_up_down_off);
+ ctx->input = qmi_message_dms_set_operating_mode_input_new ();
+ qmi_message_dms_set_operating_mode_input_set_mode (ctx->input, mode, NULL);
+ ctx->step = SET_OPERATING_MODE_STEP_FIRST;
- mm_dbg ("Setting device operating mode...");
- qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (client),
- input,
- 20,
- NULL,
- (GAsyncReadyCallback)dms_set_operating_mode_ready,
- result);
- qmi_message_dms_set_operating_mode_input_unref (input);
+ set_operating_mode_context_step (ctx);
}
static void