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
This commit is contained in:
Aleksander Morgado
2015-02-07 21:39:00 +01:00
parent b6f8e5f08d
commit a83d1c70b1
2 changed files with 144 additions and 45 deletions

View File

@@ -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

View File

@@ -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)
qmi_message_dms_set_operating_mode_output_unref (output);
if (!qmi_message_dms_set_operating_mode_output_get_result (output, &error)) {
QmiDmsOperatingMode mode;
g_simple_async_result_complete (simple);
g_object_unref (simple);
/* 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;
}
/* 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);
/* 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;
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;
}
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