broadband-modem-qmi: implement initial allowed mode loading using QMI
This commit is contained in:
@@ -48,6 +48,10 @@ struct _MMBroadbandModemQmiPrivate {
|
|||||||
gchar *meid;
|
gchar *meid;
|
||||||
gchar *esn;
|
gchar *esn;
|
||||||
|
|
||||||
|
/* Allowed mode related */
|
||||||
|
gboolean has_mode_preference_in_get_system_selection_preference;
|
||||||
|
gboolean has_get_technology_preference;
|
||||||
|
|
||||||
/* Signal quality related */
|
/* Signal quality related */
|
||||||
gboolean has_get_signal_info;
|
gboolean has_get_signal_info;
|
||||||
};
|
};
|
||||||
@@ -1614,6 +1618,317 @@ modem_factory_reset (MMIfaceModem *self,
|
|||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Load allowed modes (Modem interface) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMBroadbandModemQmi *self;
|
||||||
|
QmiClientNas *client;
|
||||||
|
GSimpleAsyncResult *result;
|
||||||
|
gboolean run_get_system_selection_preference;
|
||||||
|
gboolean run_get_technology_preference;
|
||||||
|
} LoadAllowedModesContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMModemMode allowed;
|
||||||
|
MMModemMode preferred;
|
||||||
|
} LoadAllowedModesResult;
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_allowed_modes_context_complete_and_free (LoadAllowedModesContext *ctx)
|
||||||
|
{
|
||||||
|
g_simple_async_result_complete_in_idle (ctx->result);
|
||||||
|
g_object_unref (ctx->result);
|
||||||
|
g_object_unref (ctx->client);
|
||||||
|
g_object_unref (ctx->self);
|
||||||
|
g_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
load_allowed_modes_finish (MMIfaceModem *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
MMModemMode *allowed,
|
||||||
|
MMModemMode *preferred,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
LoadAllowedModesResult *result;
|
||||||
|
|
||||||
|
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
result = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
|
||||||
|
*allowed = result->allowed;
|
||||||
|
*preferred = result->preferred;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_allowed_modes_context_step (LoadAllowedModesContext *ctx);
|
||||||
|
|
||||||
|
static MMModemMode
|
||||||
|
modem_mode_from_qmi_radio_technology_preference (QmiNasRatModePreference qmi)
|
||||||
|
{
|
||||||
|
MMModemMode mode = MM_MODEM_MODE_NONE;
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP2) {
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_ANALOG)
|
||||||
|
mode |= MM_MODEM_MODE_CS; /* AMPS */
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_DIGITAL)
|
||||||
|
mode |= MM_MODEM_MODE_2G; /* CDMA */
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_HDR)
|
||||||
|
mode |= MM_MODEM_MODE_3G; /* EV-DO */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_3GPP) {
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_ANALOG)
|
||||||
|
mode |= (MM_MODEM_MODE_CS | MM_MODEM_MODE_2G); /* GSM */
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_DIGITAL)
|
||||||
|
mode |= MM_MODEM_MODE_3G; /* WCDMA */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_LTE)
|
||||||
|
mode |= MM_MODEM_MODE_4G;
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_technology_preference_ready (QmiClientNas *client,
|
||||||
|
GAsyncResult *res,
|
||||||
|
LoadAllowedModesContext *ctx)
|
||||||
|
{
|
||||||
|
LoadAllowedModesResult *result = NULL;
|
||||||
|
QmiMessageNasGetTechnologyPreferenceOutput *output = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
output = qmi_client_nas_get_technology_preference_finish (client, res, &error);
|
||||||
|
if (!output) {
|
||||||
|
if (g_error_matches (error,
|
||||||
|
QMI_CORE_ERROR,
|
||||||
|
QMI_CORE_ERROR_UNSUPPORTED))
|
||||||
|
ctx->self->priv->has_get_technology_preference = FALSE;
|
||||||
|
mm_dbg ("QMI operation failed: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
} else if (!qmi_message_nas_get_technology_preference_output_get_result (output, &error)) {
|
||||||
|
mm_dbg ("Couldn't get technology preference: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
} else {
|
||||||
|
MMModemMode allowed;
|
||||||
|
QmiNasRadioTechnologyPreference preference_mask;
|
||||||
|
|
||||||
|
qmi_message_nas_get_technology_preference_output_get_active (
|
||||||
|
output,
|
||||||
|
&preference_mask,
|
||||||
|
NULL, /* duration */
|
||||||
|
NULL);
|
||||||
|
allowed = modem_mode_from_qmi_radio_technology_preference (preference_mask);
|
||||||
|
if (allowed == MM_MODEM_MODE_NONE) {
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
str = qmi_nas_radio_technology_preference_build_string_from_mask (preference_mask);
|
||||||
|
mm_dbg ("Unsupported modes reported: '%s'", str);
|
||||||
|
g_free (str);
|
||||||
|
} else {
|
||||||
|
/* We got a valid value from here */
|
||||||
|
result = g_new (LoadAllowedModesResult, 1);
|
||||||
|
result->allowed = allowed;
|
||||||
|
result->preferred = MM_MODEM_MODE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output)
|
||||||
|
qmi_message_nas_get_technology_preference_output_unref (output);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
ctx->run_get_technology_preference = FALSE;
|
||||||
|
load_allowed_modes_context_step (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_simple_async_result_set_op_res_gpointer (
|
||||||
|
ctx->result,
|
||||||
|
result,
|
||||||
|
(GDestroyNotify)g_free);
|
||||||
|
load_allowed_modes_context_complete_and_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MMModemMode
|
||||||
|
modem_mode_from_qmi_rat_mode_preference (QmiNasRatModePreference qmi)
|
||||||
|
{
|
||||||
|
MMModemMode mode = MM_MODEM_MODE_NONE;
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X)
|
||||||
|
mode |= MM_MODEM_MODE_2G;
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO)
|
||||||
|
mode |= MM_MODEM_MODE_3G;
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_GSM)
|
||||||
|
mode |= MM_MODEM_MODE_2G;
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_UMTS)
|
||||||
|
mode |= MM_MODEM_MODE_3G;
|
||||||
|
|
||||||
|
if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_LTE)
|
||||||
|
mode |= MM_MODEM_MODE_4G;
|
||||||
|
|
||||||
|
/* Assume CS if 2G supported */
|
||||||
|
if (mode & MM_MODEM_MODE_2G)
|
||||||
|
mode |= MM_MODEM_MODE_CS;
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MMModemMode
|
||||||
|
modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (QmiNasGsmWcdmaAcquisitionOrderPreference qmi)
|
||||||
|
{
|
||||||
|
switch (qmi) {
|
||||||
|
case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC:
|
||||||
|
return MM_MODEM_MODE_NONE;
|
||||||
|
case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_GSM:
|
||||||
|
return MM_MODEM_MODE_2G;
|
||||||
|
case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_WCDMA:
|
||||||
|
return MM_MODEM_MODE_3G;
|
||||||
|
default:
|
||||||
|
mm_dbg ("Unknown acquisition order preference: '%s'",
|
||||||
|
qmi_nas_gsm_wcdma_acquisition_order_preference_get_string (qmi));
|
||||||
|
return MM_MODEM_MODE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
allowed_modes_get_system_selection_preference_ready (QmiClientNas *client,
|
||||||
|
GAsyncResult *res,
|
||||||
|
LoadAllowedModesContext *ctx)
|
||||||
|
{
|
||||||
|
LoadAllowedModesResult *result = NULL;
|
||||||
|
QmiMessageNasGetSystemSelectionPreferenceOutput *output = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
QmiNasRatModePreference mode_preference_mask = 0;
|
||||||
|
|
||||||
|
output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error);
|
||||||
|
if (!output) {
|
||||||
|
if (g_error_matches (error,
|
||||||
|
QMI_CORE_ERROR,
|
||||||
|
QMI_CORE_ERROR_UNSUPPORTED))
|
||||||
|
ctx->self->priv->has_get_technology_preference = FALSE;
|
||||||
|
mm_dbg ("QMI operation failed: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
} else if (!qmi_message_nas_get_system_selection_preference_output_get_result (output, &error)) {
|
||||||
|
mm_dbg ("Couldn't get system selection preference: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
} else if (!qmi_message_nas_get_system_selection_preference_output_get_mode_preference (
|
||||||
|
output,
|
||||||
|
&mode_preference_mask,
|
||||||
|
NULL)) {
|
||||||
|
/* Assuming here that Get System Selection Preference reports *always* all
|
||||||
|
* optional fields that the current message version supports */
|
||||||
|
ctx->self->priv->has_get_technology_preference = FALSE;
|
||||||
|
mm_dbg ("Mode preference not reported in system selection preference");
|
||||||
|
} else {
|
||||||
|
MMModemMode allowed;
|
||||||
|
|
||||||
|
allowed = modem_mode_from_qmi_rat_mode_preference (mode_preference_mask);
|
||||||
|
if (allowed == MM_MODEM_MODE_NONE) {
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
str = qmi_nas_rat_mode_preference_build_string_from_mask (mode_preference_mask);
|
||||||
|
mm_dbg ("Unsupported modes reported: '%s'", str);
|
||||||
|
g_free (str);
|
||||||
|
} else {
|
||||||
|
QmiNasGsmWcdmaAcquisitionOrderPreference gsm_or_wcdma;
|
||||||
|
|
||||||
|
/* We got a valid value from here */
|
||||||
|
result = g_new (LoadAllowedModesResult, 1);
|
||||||
|
result->allowed = allowed;
|
||||||
|
result->preferred = MM_MODEM_MODE_NONE;
|
||||||
|
|
||||||
|
if (mode_preference_mask & QMI_NAS_RAT_MODE_PREFERENCE_GSM &&
|
||||||
|
mode_preference_mask & QMI_NAS_RAT_MODE_PREFERENCE_UMTS &&
|
||||||
|
qmi_message_nas_get_system_selection_preference_output_get_gsm_wcdma_acquisition_order_preference (
|
||||||
|
output,
|
||||||
|
&gsm_or_wcdma,
|
||||||
|
NULL)) {
|
||||||
|
result->preferred = modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (gsm_or_wcdma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output)
|
||||||
|
qmi_message_nas_get_system_selection_preference_output_unref (output);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
/* Try with the deprecated command */
|
||||||
|
ctx->run_get_system_selection_preference = FALSE;
|
||||||
|
load_allowed_modes_context_step (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_simple_async_result_set_op_res_gpointer (
|
||||||
|
ctx->result,
|
||||||
|
result,
|
||||||
|
(GDestroyNotify)g_free);
|
||||||
|
load_allowed_modes_context_complete_and_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_allowed_modes_context_step (LoadAllowedModesContext *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->run_get_system_selection_preference) {
|
||||||
|
qmi_client_nas_get_system_selection_preference (
|
||||||
|
ctx->client,
|
||||||
|
NULL, /* no input */
|
||||||
|
5,
|
||||||
|
NULL, /* cancellable */
|
||||||
|
(GAsyncReadyCallback)allowed_modes_get_system_selection_preference_ready,
|
||||||
|
ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->run_get_technology_preference) {
|
||||||
|
qmi_client_nas_get_technology_preference (
|
||||||
|
ctx->client,
|
||||||
|
NULL, /* no input */
|
||||||
|
5,
|
||||||
|
NULL, /* cancellable */
|
||||||
|
(GAsyncReadyCallback)get_technology_preference_ready,
|
||||||
|
ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_simple_async_result_set_error (
|
||||||
|
ctx->result,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_UNSUPPORTED,
|
||||||
|
"Loading allowed modes is not supported by this device");
|
||||||
|
load_allowed_modes_context_complete_and_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_allowed_modes (MMIfaceModem *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LoadAllowedModesContext *ctx;
|
||||||
|
QmiClient *client = NULL;
|
||||||
|
|
||||||
|
if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
|
||||||
|
QMI_SERVICE_NAS, &client,
|
||||||
|
callback, user_data))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx = g_new0 (LoadAllowedModesContext, 1);
|
||||||
|
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,
|
||||||
|
load_allowed_modes);
|
||||||
|
ctx->run_get_system_selection_preference = ctx->self->priv->has_mode_preference_in_get_system_selection_preference;
|
||||||
|
ctx->run_get_technology_preference = ctx->self->priv->has_get_technology_preference;
|
||||||
|
|
||||||
|
load_allowed_modes_context_step (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* IMEI loading (3GPP interface) */
|
/* IMEI loading (3GPP interface) */
|
||||||
|
|
||||||
@@ -2298,6 +2613,8 @@ mm_broadband_modem_qmi_init (MMBroadbandModemQmi *self)
|
|||||||
|
|
||||||
/* Always try to use the newest command available first */
|
/* Always try to use the newest command available first */
|
||||||
self->priv->has_get_signal_info = TRUE;
|
self->priv->has_get_signal_info = TRUE;
|
||||||
|
self->priv->has_mode_preference_in_get_system_selection_preference = TRUE;
|
||||||
|
self->priv->has_get_technology_preference = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2358,6 +2675,8 @@ iface_modem_init (MMIfaceModem *iface)
|
|||||||
iface->load_supported_charsets_finish = NULL;
|
iface->load_supported_charsets_finish = NULL;
|
||||||
iface->setup_charset = NULL;
|
iface->setup_charset = NULL;
|
||||||
iface->setup_charset_finish = NULL;
|
iface->setup_charset_finish = NULL;
|
||||||
|
iface->load_allowed_modes = load_allowed_modes;
|
||||||
|
iface->load_allowed_modes_finish = load_allowed_modes_finish;
|
||||||
iface->modem_power_down = modem_power_down;
|
iface->modem_power_down = modem_power_down;
|
||||||
iface->modem_power_down_finish = modem_power_up_down_finish;
|
iface->modem_power_down_finish = modem_power_up_down_finish;
|
||||||
iface->load_signal_quality = load_signal_quality;
|
iface->load_signal_quality = load_signal_quality;
|
||||||
|
Reference in New Issue
Block a user