diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2015-02-07 21:39:00 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2015-02-07 21:39:15 +0100 |
commit | a83d1c70b1f433bcb9a33b4cb1b5e3032050a104 (patch) | |
tree | 2daf0143283a7000da746f2ea112e432789c317b | |
parent | b6f8e5f08de8860b4c54609a3648cb86a04244ea (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.ac | 2 | ||||
-rw-r--r-- | src/mm-broadband-modem-qmi.c | 185 |
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 |