diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-05-29 12:41:49 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-06-05 19:15:14 +0200 |
commit | 45ceba76924f184ed9e12ba3d35e00a55ad3a197 (patch) | |
tree | c413d3e29a64eb86340e964ec48e67d8a66c6f76 /src | |
parent | 212d00c529ee07131bf3b71a8759dca49292c059 (diff) |
api,introspection: 'SupportedModes' is now a list of possible combinations
Instead of just a mask of MMModemMode values, we now provide a list of the
allowed and preferred mode combinations supported by the modem. E.g.:
$> sudo mmcli -m 0
-------------------------
Modes | supported: 'allowed: 2g; preferred: none
| allowed: 3g; preferred: none
| allowed: 2g, 3g; preferred: none
| allowed: 2g, 3g; preferred: 2g
| allowed: 2g, 3g; preferred: 3g
| allowed: 4g; preferred: none
| allowed: 2g, 3g, 4g; preferred: none'
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem-mbim.c | 70 | ||||
-rw-r--r-- | src/mm-broadband-modem-qmi.c | 143 | ||||
-rw-r--r-- | src/mm-broadband-modem.c | 23 | ||||
-rw-r--r-- | src/mm-iface-modem.c | 206 | ||||
-rw-r--r-- | src/mm-iface-modem.h | 19 | ||||
-rw-r--r-- | src/mm-modem-helpers-qmi.c | 23 | ||||
-rw-r--r-- | src/mm-modem-helpers-qmi.h | 2 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 47 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 3 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 124 |
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); |