aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem-mbim.c70
-rw-r--r--src/mm-broadband-modem-qmi.c143
-rw-r--r--src/mm-broadband-modem.c23
-rw-r--r--src/mm-iface-modem.c206
-rw-r--r--src/mm-iface-modem.h19
-rw-r--r--src/mm-modem-helpers-qmi.c23
-rw-r--r--src/mm-modem-helpers-qmi.h2
-rw-r--r--src/mm-modem-helpers.c47
-rw-r--r--src/mm-modem-helpers.h3
-rw-r--r--src/tests/test-modem-helpers.c124
10 files changed, 513 insertions, 147 deletions
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c
index cdb5ea64..5c9f3478 100644
--- a/src/mm-broadband-modem-mbim.c
+++ b/src/mm-broadband-modem-mbim.c
@@ -370,62 +370,74 @@ modem_load_device_identifier (MMIfaceModem *self,
/*****************************************************************************/
/* Supported modes loading (Modem interface) */
-static MMModemMode
-modem_load_supported_modes_finish (MMIfaceModem *_self,
+static GArray *
+modem_load_supported_modes_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
- MMModemMode mask;
+ return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
+}
+
+static void
+modem_load_supported_modes (MMIfaceModem *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
+ GArray *combinations;
+ MMModemModeCombination mode;
+ GSimpleAsyncResult *result;
+ MMModemMode all;
+
+ /* Just complete */
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_load_supported_modes);
+
if (self->priv->caps_data_class == 0) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Data class not given in device capabilities");
- return MM_MODEM_MODE_NONE;
+ g_simple_async_result_set_error (result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Data class not given in device capabilities");
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ return;
}
- mask = 0;
+ all = 0;
/* 3GPP... */
if (self->priv->caps_data_class & (MBIM_DATA_CLASS_GPRS |
MBIM_DATA_CLASS_EDGE))
- mask |= MM_MODEM_MODE_2G;
+ all |= MM_MODEM_MODE_2G;
if (self->priv->caps_data_class & (MBIM_DATA_CLASS_UMTS |
MBIM_DATA_CLASS_HSDPA |
MBIM_DATA_CLASS_HSUPA))
- mask |= MM_MODEM_MODE_3G;
+ all |= MM_MODEM_MODE_3G;
if (self->priv->caps_data_class & MBIM_DATA_CLASS_LTE)
- mask |= MM_MODEM_MODE_4G;
+ all |= MM_MODEM_MODE_4G;
/* 3GPP2... */
if (self->priv->caps_data_class & MBIM_DATA_CLASS_1XRTT)
- mask |= MM_MODEM_MODE_2G;
+ all |= MM_MODEM_MODE_2G;
if (self->priv->caps_data_class & (MBIM_DATA_CLASS_1XEVDO |
MBIM_DATA_CLASS_1XEVDO_REVA |
MBIM_DATA_CLASS_1XEVDV |
MBIM_DATA_CLASS_3XRTT |
MBIM_DATA_CLASS_1XEVDO_REVB))
- mask |= MM_MODEM_MODE_3G;
+ all |= MM_MODEM_MODE_3G;
if (self->priv->caps_data_class & MBIM_DATA_CLASS_UMB)
- mask |= MM_MODEM_MODE_4G;
+ all |= MM_MODEM_MODE_4G;
- return mask;
-}
-
-static void
-modem_load_supported_modes (MMIfaceModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *result;
+ /* Build a mask with all supported modes */
+ combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
+ mode.allowed = all;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
- /* Just complete */
- result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- modem_load_supported_modes);
+ g_simple_async_result_set_op_res_gpointer (result, combinations, (GDestroyNotify) g_array_unref);
g_simple_async_result_complete_in_idle (result);
g_object_unref (result);
}
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 77d93754..853d940f 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -65,6 +65,9 @@ struct _MMBroadbandModemQmiPrivate {
gchar *meid;
gchar *esn;
+ /* Cached supported radio interfaces; in order to load supported modes */
+ GArray *supported_radio_interfaces;
+
/* Cached supported frequency bands; in order to handle ANY */
GArray *supported_bands;
@@ -554,6 +557,20 @@ modem_load_current_capabilities (MMIfaceModem *self,
/*****************************************************************************/
/* Modem Capabilities loading (Modem interface) */
+typedef struct {
+ MMBroadbandModemQmi *self;
+ GSimpleAsyncResult *result;
+} LoadModemCapabilitiesContext;
+
+static void
+load_modem_capabilities_context_complete_and_free (LoadModemCapabilitiesContext *ctx)
+{
+ g_simple_async_result_complete (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->self);
+ g_slice_free (LoadModemCapabilitiesContext, ctx);
+}
+
static MMModemCapability
modem_load_modem_capabilities_finish (MMIfaceModem *self,
GAsyncResult *res,
@@ -577,7 +594,7 @@ modem_load_modem_capabilities_finish (MMIfaceModem *self,
static void
dms_get_capabilities_ready (QmiClientDms *client,
GAsyncResult *res,
- GSimpleAsyncResult *simple)
+ LoadModemCapabilitiesContext *ctx)
{
QmiMessageDmsGetCapabilitiesOutput *output = NULL;
GError *error = NULL;
@@ -585,10 +602,10 @@ dms_get_capabilities_ready (QmiClientDms *client,
output = qmi_client_dms_get_capabilities_finish (client, res, &error);
if (!output) {
g_prefix_error (&error, "QMI operation failed: ");
- g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_take_error (ctx->result, error);
} else if (!qmi_message_dms_get_capabilities_output_get_result (output, &error)) {
g_prefix_error (&error, "Couldn't get modem capabilities: ");
- g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_take_error (ctx->result, error);
} else {
guint i;
guint mask = MM_MODEM_CAPABILITY_NONE;
@@ -609,7 +626,12 @@ dms_get_capabilities_ready (QmiClientDms *client,
i));
}
- g_simple_async_result_set_op_res_gpointer (simple,
+ /* Cache supported radio interfaces */
+ if (ctx->self->priv->supported_radio_interfaces)
+ g_array_unref (ctx->self->priv->supported_radio_interfaces);
+ ctx->self->priv->supported_radio_interfaces = g_array_ref (radio_interface_list);
+
+ g_simple_async_result_set_op_res_gpointer (ctx->result,
GUINT_TO_POINTER (mask),
NULL);
}
@@ -617,8 +639,7 @@ dms_get_capabilities_ready (QmiClientDms *client,
if (output)
qmi_message_dms_get_capabilities_output_unref (output);
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ load_modem_capabilities_context_complete_and_free (ctx);
}
static void
@@ -626,7 +647,7 @@ modem_load_modem_capabilities (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GSimpleAsyncResult *result;
+ LoadModemCapabilitiesContext *ctx;
QmiClient *client = NULL;
if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
@@ -634,10 +655,12 @@ modem_load_modem_capabilities (MMIfaceModem *self,
callback, user_data))
return;
- result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- modem_load_modem_capabilities);
+ ctx = g_slice_new (LoadModemCapabilitiesContext);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_load_modem_capabilities);
mm_dbg ("loading modem capabilities...");
qmi_client_dms_get_capabilities (QMI_CLIENT_DMS (client),
@@ -645,7 +668,7 @@ modem_load_modem_capabilities (MMIfaceModem *self,
5,
NULL,
(GAsyncReadyCallback)dms_get_capabilities_ready,
- result);
+ ctx);
}
/*****************************************************************************/
@@ -1711,37 +1734,89 @@ set_current_bands (MMIfaceModem *_self,
/*****************************************************************************/
/* Load supported modes (Modem interface) */
-static MMModemMode
+static GArray *
modem_load_supported_modes_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
- return (MMModemMode)GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
- G_SIMPLE_ASYNC_RESULT (res)));
+ return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
}
static void
-modem_load_supported_modes (MMIfaceModem *self,
+modem_load_supported_modes (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
GSimpleAsyncResult *result;
- MMModemMode mode;
-
- /* For QMI-powered modems, it is safe to assume they do 2G and 3G */
- mode = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
-
- /* Then, if the modem has LTE caps, it does 4G */
- if (mm_iface_modem_is_3gpp_lte (MM_IFACE_MODEM (self)))
- mode |= MM_MODEM_MODE_4G;
+ GArray *all;
+ GArray *combinations;
+ GArray *filtered;
+ MMModemModeCombination mode;
+ guint i;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
modem_load_supported_modes);
- g_simple_async_result_set_op_res_gpointer (result,
- GUINT_TO_POINTER (mode),
- NULL);
+
+ if (!self->priv->supported_radio_interfaces) {
+ g_simple_async_result_set_error (result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Cannot load supported modes, no radio interface list");
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ return;
+ }
+
+ /* Build all, based on the supported radio interfaces */
+ mode.allowed = MM_MODEM_MODE_NONE;
+ for (i = 0; i < self->priv->supported_radio_interfaces->len; i++)
+ mode.allowed |= mm_modem_mode_from_qmi_radio_interface (g_array_index (self->priv->supported_radio_interfaces,
+ QmiDmsRadioInterface,
+ i));
+ mode.preferred = MM_MODEM_MODE_NONE;
+ all = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
+ g_array_append_val (all, mode);
+
+ /* Build combinations */
+ combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 7);
+ /* 2G only */
+ mode.allowed = MM_MODEM_MODE_2G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 3G only */
+ mode.allowed = MM_MODEM_MODE_3G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 2G and 3G */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 2G and 3G, 2G preferred */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
+ mode.preferred = MM_MODEM_MODE_2G;
+ g_array_append_val (combinations, mode);
+ /* 2G and 3G, 3G preferred */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
+ mode.preferred = MM_MODEM_MODE_3G;
+ g_array_append_val (combinations, mode);
+ /* 4G only */
+ mode.allowed = MM_MODEM_MODE_4G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 2G, 3G and 4G */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+
+ /* Filter out those unsupported modes */
+ filtered = mm_filter_supported_modes (all, combinations);
+ g_array_unref (all);
+ g_array_unref (combinations);
+
+ g_simple_async_result_set_op_res_gpointer (result, filtered, (GDestroyNotify) g_array_unref);
g_simple_async_result_complete_in_idle (result);
g_object_unref (result);
}
@@ -2842,8 +2917,16 @@ set_allowed_modes (MMIfaceModem *self,
callback,
user_data,
set_allowed_modes);
- ctx->allowed = allowed;
- ctx->preferred = preferred;
+
+ if (allowed == MM_MODEM_MODE_ANY && ctx->preferred == MM_MODEM_MODE_NONE) {
+ ctx->allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
+ ctx->preferred = MM_MODEM_MODE_NONE;
+ if (mm_iface_modem_is_3gpp_lte (self))
+ ctx->allowed |= MM_MODEM_MODE_4G;
+ } else {
+ ctx->allowed = allowed;
+ ctx->preferred = preferred;
+ }
/* System selection preference introduced in NAS 1.1 */
ctx->run_set_system_selection_preference = qmi_client_check_version (client, 1, 1);
@@ -8074,6 +8157,8 @@ finalize (GObject *object)
g_free (self->priv->current_operator_description);
if (self->priv->supported_bands)
g_array_unref (self->priv->supported_bands);
+ if (self->priv->supported_radio_interfaces)
+ g_array_unref (self->priv->supported_radio_interfaces);
G_OBJECT_CLASS (mm_broadband_modem_qmi_parent_class)->finalize (object);
}
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 71045484..985ae354 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -1286,19 +1286,28 @@ load_supported_modes_context_complete_and_free (LoadSupportedModesContext *ctx)
g_simple_async_result_complete (ctx->result);
g_object_unref (ctx->result);
g_object_unref (ctx->self);
- g_free (ctx);
+ g_slice_free (LoadSupportedModesContext, ctx);
}
-static MMModemMode
+static GArray *
modem_load_supported_modes_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
+ GArray *modes;
+ MMModemModeCombination mode;
+
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
- return MM_MODEM_MODE_NONE;
+ return NULL;
+
+ /* Build a mask with all supported modes */
+ modes = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
+ mode.allowed = (MMModemMode) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (res)));
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (modes, mode);
- return (MMModemMode)GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
- G_SIMPLE_ASYNC_RESULT (res)));
+ return modes;
}
static void load_supported_modes_step (LoadSupportedModesContext *ctx);
@@ -1515,8 +1524,8 @@ modem_load_supported_modes (MMIfaceModem *self,
{
LoadSupportedModesContext *ctx;
- mm_dbg ("loading initial supported modes...");
- ctx = g_new0 (LoadSupportedModesContext, 1);
+ mm_dbg ("loading supported modes...");
+ ctx = g_slice_new0 (LoadSupportedModesContext);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index 8e264629..135f18f0 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -2178,9 +2178,11 @@ mm_iface_modem_set_allowed_modes (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ GArray *supported;
SetAllowedModesContext *ctx;
- MMModemMode supported;
- MMModemMode not_supported;
+ MMModemMode current_allowed;
+ MMModemMode current_preferred;
+ guint i;
/* If setting allowed modes is not implemented, report an error */
if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_allowed_modes ||
@@ -2201,6 +2203,8 @@ mm_iface_modem_set_allowed_modes (MMIfaceModem *self,
callback,
user_data,
mm_iface_modem_set_allowed_modes);
+ ctx->allowed = allowed;
+ ctx->preferred = preferred;
g_object_get (self,
MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
NULL);
@@ -2214,43 +2218,58 @@ mm_iface_modem_set_allowed_modes (MMIfaceModem *self,
}
/* Get list of supported modes */
- supported = mm_gdbus_modem_get_supported_modes (ctx->skeleton);
-
- /* Whenever we get 'any', just reset to be equal to the list of supported modes */
- if (allowed == MM_MODEM_MODE_ANY)
- allowed = supported;
-
- ctx->allowed = allowed;
- ctx->preferred = preferred;
+ supported = mm_common_mode_combinations_variant_to_garray (
+ mm_gdbus_modem_get_supported_modes (ctx->skeleton));
- /* Check if we already are in the requested setup */
- if (mm_gdbus_modem_get_allowed_modes (ctx->skeleton) == allowed &&
- mm_gdbus_modem_get_preferred_mode (ctx->skeleton) == preferred) {
- g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ /* Don't allow mode switchin if only one item given in the supported list */
+ if (supported->len == 1) {
+ g_simple_async_result_set_error (ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot change modes: only one combination supported");
+ g_array_unref (supported);
set_allowed_modes_context_complete_and_free (ctx);
return;
}
- /* Check if any of the modes being allowed is not supported */
- not_supported = ((supported ^ allowed) & allowed);
+ if (allowed == MM_MODEM_MODE_ANY &&
+ preferred == MM_MODEM_MODE_NONE) {
+ /* Allow allowed=ANY & preferred=NONE, all plugins should support it */
+ } else {
+ gboolean matched = FALSE;
+
+ /* Check if the given combination is supported */
+ for (i = 0; !matched && i < supported->len; i++) {
+ MMModemModeCombination *supported_mode;
+
+ supported_mode = &g_array_index (supported, MMModemModeCombination, i);
+ if ((supported_mode->allowed == MM_MODEM_MODE_ANY &&
+ supported_mode->preferred == MM_MODEM_MODE_NONE) ||
+ (supported_mode->allowed == allowed &&
+ supported_mode->preferred == preferred)) {
+ matched = TRUE;
+ }
+ }
- /* Ensure allowed is a subset of supported */
- if (not_supported) {
- gchar *not_supported_str;
- gchar *supported_str;
+ if (!matched) {
+ g_simple_async_result_set_error (ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "The given combination of allowed and preferred modes is not supported");
+ g_array_unref (supported);
+ set_allowed_modes_context_complete_and_free (ctx);
+ return;
+ }
+ }
- not_supported_str = mm_modem_mode_build_string_from_mask (not_supported);
- supported_str = mm_modem_mode_build_string_from_mask (supported);
- g_simple_async_result_set_error (ctx->result,
- MM_CORE_ERROR,
- MM_CORE_ERROR_UNSUPPORTED,
- "Some of the allowed modes (%s) are not "
- "supported (%s)",
- not_supported_str,
- supported_str);
- g_free (supported_str);
- g_free (not_supported_str);
+ g_array_unref (supported);
+ /* Check if we already are in the requested setup */
+ current_allowed = mm_gdbus_modem_get_allowed_modes (ctx->skeleton);
+ current_preferred = mm_gdbus_modem_get_preferred_mode (ctx->skeleton);
+ if (current_allowed == allowed &&
+ current_preferred == preferred) {
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
set_allowed_modes_context_complete_and_free (ctx);
return;
}
@@ -2275,6 +2294,8 @@ mm_iface_modem_set_allowed_modes (MMIfaceModem *self,
return;
}
+ ctx->allowed = allowed;
+ ctx->preferred = preferred;
MM_IFACE_MODEM_GET_INTERFACE (self)->set_allowed_modes (self,
allowed,
preferred,
@@ -3209,9 +3230,8 @@ load_allowed_modes_ready (MMIfaceModem *self,
mm_warn ("couldn't load current allowed/preferred modes: '%s'", error->message);
g_error_free (error);
- /* If errors getting allowed modes, assume allowed=supported,
- * and none preferred */
- allowed = mm_gdbus_modem_get_supported_modes (ctx->skeleton);
+ /* If errors getting allowed modes, assume ANY/NONE */
+ allowed = MM_MODEM_MODE_ANY;
preferred = MM_MODEM_MODE_NONE;
}
@@ -3364,10 +3384,9 @@ interface_enabling_step (EnablingContext *ctx)
return;
}
- /* If no way to get allowed modes, assume allowed=supported,
+ /* If no way to get allowed modes, assume allowed=any,
* and none preferred */
- mm_gdbus_modem_set_allowed_modes (ctx->skeleton,
- mm_gdbus_modem_get_supported_modes (ctx->skeleton));
+ mm_gdbus_modem_set_allowed_modes (ctx->skeleton, MM_MODEM_MODE_ANY);
mm_gdbus_modem_set_preferred_mode (ctx->skeleton, MM_MODEM_MODE_NONE);
/* Fall down to next step */
ctx->step++;
@@ -3652,13 +3671,13 @@ load_supported_modes_ready (MMIfaceModem *self,
InitializationContext *ctx)
{
GError *error = NULL;
- MMModemMode modes;
-
- modes = MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_modes_finish (self, res, &error);
+ GArray *modes_array;
- if (modes != MM_MODEM_MODE_NONE) {
- mm_gdbus_modem_set_supported_modes (ctx->skeleton, modes);
- mm_gdbus_modem_set_allowed_modes (ctx->skeleton, modes);
+ modes_array = MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_modes_finish (self, res, &error);
+ if (modes_array != NULL) {
+ mm_gdbus_modem_set_supported_modes (ctx->skeleton,
+ mm_common_mode_combinations_garray_to_variant (modes_array));
+ g_array_unref (modes_array);
}
if (error) {
@@ -4010,18 +4029,30 @@ interface_initialization_step (InitializationContext *ctx)
ctx->step++;
case INITIALIZATION_STEP_SUPPORTED_MODES:
- g_assert (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_modes != NULL);
- g_assert (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_modes_finish != NULL);
+ if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_modes != NULL &&
+ MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_modes_finish != NULL) {
+ GArray *supported_modes;
+ MMModemModeCombination *mode = NULL;
+
+ supported_modes = (mm_common_mode_combinations_variant_to_garray (
+ mm_gdbus_modem_get_supported_modes (ctx->skeleton)));
+
+ /* Supported modes are meant to be loaded only once during the whole
+ * lifetime of the modem. Therefore, if we already have them loaded,
+ * don't try to load them again. */
+ if (supported_modes->len == 1)
+ mode = &g_array_index (supported_modes, MMModemModeCombination, 0);
+ if (supported_modes->len == 0 ||
+ (mode && mode->allowed == MM_MODEM_MODE_ANY && mode->preferred == MM_MODEM_MODE_NONE)) {
+ MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_modes (
+ ctx->self,
+ (GAsyncReadyCallback)load_supported_modes_ready,
+ ctx);
+ g_array_unref (supported_modes);
+ return;
+ }
- /* Supported modes are meant to be loaded only once during the whole
- * lifetime of the modem. Therefore, if we already have them loaded,
- * don't try to load them again. */
- if (mm_gdbus_modem_get_supported_modes (ctx->skeleton) == MM_MODEM_MODE_NONE) {
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_modes (
- ctx->self,
- (GAsyncReadyCallback)load_supported_modes_ready,
- ctx);
- return;
+ g_array_unref (supported_modes);
}
/* Fall down to next step */
ctx->step++;
@@ -4257,7 +4288,7 @@ mm_iface_modem_initialize (MMIfaceModem *self,
mm_gdbus_modem_set_unlock_retries (skeleton, 0);
mm_gdbus_modem_set_access_technologies (skeleton, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
mm_gdbus_modem_set_signal_quality (skeleton, g_variant_new ("(ub)", 0, FALSE));
- mm_gdbus_modem_set_supported_modes (skeleton, MM_MODEM_MODE_NONE);
+ mm_gdbus_modem_set_supported_modes (skeleton, mm_common_build_mode_combinations_default ());
mm_gdbus_modem_set_allowed_modes (skeleton, MM_MODEM_MODE_NONE);
mm_gdbus_modem_set_preferred_mode (skeleton, MM_MODEM_MODE_NONE);
mm_gdbus_modem_set_supported_bands (skeleton, mm_common_build_bands_unknown ());
@@ -4357,10 +4388,12 @@ mm_iface_modem_get_access_technologies (MMIfaceModem *self)
/*****************************************************************************/
-MMModemMode
-mm_iface_modem_get_supported_modes (MMIfaceModem *self)
+static gboolean
+find_supported_mode (MMIfaceModem *self,
+ MMModemMode mode,
+ gboolean *only)
{
- MMModemMode supported = MM_MODEM_MODE_NONE;
+ gboolean matched = FALSE;
MmGdbusModem *skeleton;
g_object_get (self,
@@ -4368,56 +4401,85 @@ mm_iface_modem_get_supported_modes (MMIfaceModem *self)
NULL);
if (skeleton) {
- supported = mm_gdbus_modem_get_supported_modes (skeleton);
+ GArray *supported;
+ guint i;
+ guint n_unmatched = 0;
+
+ supported = mm_common_mode_combinations_variant_to_garray (
+ mm_gdbus_modem_get_supported_modes (skeleton));
+
+ /* Check if the given mode is supported */
+ for (i = 0; i < supported->len; i++) {
+ MMModemModeCombination *supported_mode;
+
+ supported_mode = &g_array_index (supported, MMModemModeCombination, i);
+ if (supported_mode->allowed & mode) {
+ matched = TRUE;
+ if (supported_mode->allowed != mode)
+ n_unmatched++;
+ } else
+ n_unmatched++;
+
+ if (matched && (only == NULL || n_unmatched > 0))
+ break;
+ }
+
+ if (only)
+ *only = (n_unmatched == 0);
+
+ g_array_unref (supported);
g_object_unref (skeleton);
}
- return supported;
+ return matched;
}
gboolean
mm_iface_modem_is_2g (MMIfaceModem *self)
{
- return (mm_iface_modem_get_supported_modes (self) & MM_MODEM_MODE_2G);
+ return find_supported_mode (self, MM_MODEM_MODE_2G, NULL);
}
gboolean
mm_iface_modem_is_2g_only (MMIfaceModem *self)
{
- MMModemMode supported;
+ gboolean only;
- supported = mm_iface_modem_get_supported_modes (self);
- return !((MM_MODEM_MODE_2G ^ supported) & supported);
+ return (find_supported_mode (self, MM_MODEM_MODE_2G, &only) ?
+ only :
+ FALSE);
}
gboolean
mm_iface_modem_is_3g (MMIfaceModem *self)
{
- return (mm_iface_modem_get_supported_modes (self) & MM_MODEM_MODE_3G);
+ return find_supported_mode (self, MM_MODEM_MODE_3G, NULL);
}
gboolean
mm_iface_modem_is_3g_only (MMIfaceModem *self)
{
- MMModemMode supported;
+ gboolean only;
- supported = mm_iface_modem_get_supported_modes (self);
- return !((MM_MODEM_MODE_3G ^ supported) & supported);
+ return (find_supported_mode (self, MM_MODEM_MODE_3G, &only) ?
+ only :
+ FALSE);
}
gboolean
mm_iface_modem_is_4g (MMIfaceModem *self)
{
- return (mm_iface_modem_get_supported_modes (self) & MM_MODEM_MODE_4G);
+ return find_supported_mode (self, MM_MODEM_MODE_4G, NULL);
}
gboolean
mm_iface_modem_is_4g_only (MMIfaceModem *self)
{
- MMModemMode supported;
+ gboolean only;
- supported = mm_iface_modem_get_supported_modes (self);
- return !((MM_MODEM_MODE_4G ^ supported) & supported);
+ return (find_supported_mode (self, MM_MODEM_MODE_4G, &only) ?
+ only :
+ FALSE);
}
/*****************************************************************************/
diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
index f14f8cba..65b0243f 100644
--- a/src/mm-iface-modem.h
+++ b/src/mm-iface-modem.h
@@ -126,9 +126,9 @@ struct _MMIfaceModem {
void (*load_supported_modes) (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data);
- MMModemMode (*load_supported_modes_finish) (MMIfaceModem *self,
- GAsyncResult *res,
- GError **error);
+ GArray * (*load_supported_modes_finish) (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error);
/* Loading of the AllowedModes and PreferredMode properties */
void (*load_allowed_modes) (MMIfaceModem *self,
@@ -328,13 +328,12 @@ gboolean mm_iface_modem_is_cdma (MMIfaceModem *self);
gboolean mm_iface_modem_is_cdma_only (MMIfaceModem *self);
/* Helpers to query supported modes */
-MMModemMode mm_iface_modem_get_supported_modes (MMIfaceModem *self);
-gboolean mm_iface_modem_is_2g (MMIfaceModem *self);
-gboolean mm_iface_modem_is_2g_only (MMIfaceModem *self);
-gboolean mm_iface_modem_is_3g (MMIfaceModem *self);
-gboolean mm_iface_modem_is_3g_only (MMIfaceModem *self);
-gboolean mm_iface_modem_is_4g (MMIfaceModem *self);
-gboolean mm_iface_modem_is_4g_only (MMIfaceModem *self);
+gboolean mm_iface_modem_is_2g (MMIfaceModem *self);
+gboolean mm_iface_modem_is_2g_only (MMIfaceModem *self);
+gboolean mm_iface_modem_is_3g (MMIfaceModem *self);
+gboolean mm_iface_modem_is_3g_only (MMIfaceModem *self);
+gboolean mm_iface_modem_is_4g (MMIfaceModem *self);
+gboolean mm_iface_modem_is_4g_only (MMIfaceModem *self);
/* Initialize Modem interface (async) */
void mm_iface_modem_initialize (MMIfaceModem *self,
diff --git a/src/mm-modem-helpers-qmi.c b/src/mm-modem-helpers-qmi.c
index efe3686d..b5267f8d 100644
--- a/src/mm-modem-helpers-qmi.c
+++ b/src/mm-modem-helpers-qmi.c
@@ -42,6 +42,29 @@ mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network)
/*****************************************************************************/
+MMModemMode
+mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network)
+{
+ switch (network) {
+ case QMI_DMS_RADIO_INTERFACE_CDMA20001X:
+ return MM_MODEM_MODE_2G;
+ case QMI_DMS_RADIO_INTERFACE_EVDO:
+ return MM_MODEM_MODE_3G;
+ case QMI_DMS_RADIO_INTERFACE_GSM:
+ return MM_MODEM_MODE_2G;
+ case QMI_DMS_RADIO_INTERFACE_UMTS:
+ return MM_MODEM_MODE_3G;
+ case QMI_DMS_RADIO_INTERFACE_LTE:
+ return MM_MODEM_MODE_4G;
+ default:
+ mm_warn ("Unhandled QMI radio interface (%u)",
+ (guint)network);
+ return MM_MODEM_MODE_NONE;
+ }
+}
+
+/*****************************************************************************/
+
/* pin1 TRUE for PIN1, FALSE for PIN2 */
MMModemLock
mm_modem_lock_from_qmi_uim_pin_status (QmiDmsUimPinStatus status,
diff --git a/src/mm-modem-helpers-qmi.h b/src/mm-modem-helpers-qmi.h
index 8da0fdd7..6eae632c 100644
--- a/src/mm-modem-helpers-qmi.h
+++ b/src/mm-modem-helpers-qmi.h
@@ -26,6 +26,8 @@
MMModemCapability mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network);
+MMModemMode mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network);
+
MMModemLock mm_modem_lock_from_qmi_uim_pin_status (QmiDmsUimPinStatus status,
gboolean pin1);
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 46265d04..6d0acb20 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -248,6 +248,53 @@ mm_new_iso8601_time (guint year,
/*****************************************************************************/
+GArray *
+mm_filter_supported_modes (const GArray *all,
+ const GArray *supported_combinations)
+{
+ MMModemModeCombination all_item;
+ guint i;
+ GArray *filtered_combinations;
+ gboolean all_item_added = FALSE;
+
+ g_return_val_if_fail (all != NULL, NULL);
+ g_return_val_if_fail (all->len == 1, NULL);
+ g_return_val_if_fail (supported_combinations != NULL, NULL);
+
+ all_item = g_array_index (all, MMModemModeCombination, 0);
+ g_return_val_if_fail (all_item.allowed != MM_MODEM_MODE_NONE, NULL);
+
+ /* We will filter out all combinations which have modes not listed in 'all' */
+ filtered_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), supported_combinations->len);
+ for (i = 0; i < supported_combinations->len; i++) {
+ MMModemModeCombination *mode;
+
+ mode = &g_array_index (supported_combinations, MMModemModeCombination, i);
+ if (!(mode->allowed & ~all_item.allowed)) {
+ /* Compare only 'allowed', *not* preferred. If there is at least one item with allowed
+ * containing all supported modes, we're already good to go. This allows us to have a
+ * default with preferred != NONE (e.g. Wavecom 2G modem with allowed=CS+2G and
+ * preferred=2G */
+ if (all_item.allowed == mode->allowed)
+ all_item_added = TRUE;
+ g_array_append_val (filtered_combinations, *mode);
+ }
+ }
+
+ if (filtered_combinations->len == 0)
+ mm_warn ("All supported mode combinations were filtered out.");
+
+ /* Add default entry with the generic mask including all items */
+ if (!all_item_added) {
+ mm_dbg ("Adding an explicit item with all supported modes allowed");
+ g_array_append_val (filtered_combinations, all_item);
+ }
+
+ return filtered_combinations;
+}
+
+/*****************************************************************************/
+
/* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */
#define CREG1 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])"
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index 80c31691..ce7c66d1 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -73,6 +73,9 @@ gchar *mm_new_iso8601_time (guint year,
gboolean have_offset,
gint offset_minutes);
+GArray *mm_filter_supported_modes (const GArray *all,
+ const GArray *supported_combinations);
+
/*****************************************************************************/
/* 3GPP specific helpers and utilities */
/*****************************************************************************/
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index 0d245b29..c61f190c 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -18,6 +18,7 @@
#include <string.h>
#include <stdlib.h>
+#include <libmm-glib.h>
#include "mm-modem-helpers.h"
#include "mm-log.h"
@@ -1931,6 +1932,127 @@ test_cdma_parse_gsn (void *f, gpointer d)
/*****************************************************************************/
+static gboolean
+find_mode_combination (GArray *modes,
+ MMModemMode allowed,
+ MMModemMode preferred)
+{
+ guint i;
+
+ for (i = 0; i < modes->len; i++) {
+ MMModemModeCombination *mode;
+
+ mode = &g_array_index (modes, MMModemModeCombination, i);
+ if (mode->allowed == allowed && mode->preferred == preferred)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GArray *
+build_mode_all (MMModemMode all_mask)
+{
+ MMModemModeCombination all_item;
+ GArray *all;
+
+ all_item.allowed = all_mask;
+ all_item.preferred = MM_MODEM_MODE_NONE;
+ all = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
+ g_array_append_val (all, all_item);
+ return all;
+}
+
+static void
+test_supported_mode_filter (void *f, gpointer d)
+{
+ MMModemModeCombination mode;
+ GArray *all;
+ GArray *combinations;
+ GArray *filtered;
+
+ /* Build array of combinations */
+ combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 5);
+
+ /* 2G only */
+ mode.allowed = MM_MODEM_MODE_2G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 3G only */
+ mode.allowed = MM_MODEM_MODE_3G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 2G and 3G */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 4G only */
+ mode.allowed = MM_MODEM_MODE_4G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 3G and 4G */
+ mode.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ /* 2G, 3G and 4G */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+
+ /* Only 2G supported */
+ all = build_mode_all (MM_MODEM_MODE_2G);
+ filtered = mm_filter_supported_modes (all, combinations);
+ g_assert_cmpuint (filtered->len, ==, 1);
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE));
+ g_array_unref (filtered);
+ g_array_unref (all);
+
+ /* Only 3G supported */
+ all = build_mode_all (MM_MODEM_MODE_3G);
+ filtered = mm_filter_supported_modes (all, combinations);
+ g_assert_cmpuint (filtered->len, ==, 1);
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE));
+ g_array_unref (filtered);
+ g_array_unref (all);
+
+ /* 2G and 3G supported */
+ all = build_mode_all (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
+ filtered = mm_filter_supported_modes (all, combinations);
+ g_assert_cmpuint (filtered->len, ==, 3);
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G), MM_MODEM_MODE_NONE));
+ g_array_unref (filtered);
+ g_array_unref (all);
+
+ /* 3G and 4G supported */
+ all = build_mode_all (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
+ filtered = mm_filter_supported_modes (all, combinations);
+ g_assert_cmpuint (filtered->len, ==, 3);
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G), MM_MODEM_MODE_NONE));
+ g_array_unref (filtered);
+ g_array_unref (all);
+
+ /* 2G, 3G and 4G supported */
+ all = build_mode_all (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
+ filtered = mm_filter_supported_modes (all, combinations);
+ g_assert_cmpuint (filtered->len, ==, 6);
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G), MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G), MM_MODEM_MODE_NONE));
+ g_assert (find_mode_combination (filtered, (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G), MM_MODEM_MODE_NONE));
+ g_array_unref (filtered);
+ g_array_unref (all);
+
+ g_array_unref (combinations);
+}
+
+/*****************************************************************************/
+
void
_mm_log (const char *loc,
const char *func,
@@ -2060,6 +2182,8 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_cmgl_response_pantech, NULL));
g_test_suite_add (suite, TESTCASE (test_cmgl_response_pantech_multiple, NULL));
+ g_test_suite_add (suite, TESTCASE (test_supported_mode_filter, NULL));
+
result = g_test_run ();
reg_test_data_free (reg_data);