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 | |
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'
35 files changed, 2047 insertions, 294 deletions
diff --git a/cli/mmcli-modem.c b/cli/mmcli-modem.c index e405307b..99233217 100644 --- a/cli/mmcli-modem.c +++ b/cli/mmcli-modem.c @@ -238,6 +238,8 @@ print_modem_info (void) gchar *modem_capabilities_string; gchar *current_capabilities_string; gchar *access_technologies_string; + MMModemModeCombination *modes = NULL; + guint n_modes = 0; gchar *supported_modes_string; gchar *allowed_modes_string; gchar *preferred_mode_string; @@ -266,6 +268,9 @@ print_modem_info (void) mm_modem_get_current_capabilities (ctx->modem)); access_technologies_string = mm_modem_access_technology_build_string_from_mask ( mm_modem_get_access_technologies (ctx->modem)); + mm_modem_get_supported_modes (ctx->modem, &modes, &n_modes); + supported_modes_string = mm_common_build_mode_combinations_string (modes, n_modes); + g_free (modes); mm_modem_get_current_bands (ctx->modem, &bands, &n_bands); current_bands_string = mm_common_build_bands_string (bands, n_bands); g_free (bands); @@ -276,8 +281,6 @@ print_modem_info (void) mm_modem_get_allowed_modes (ctx->modem)); preferred_mode_string = mm_modem_mode_build_string_from_mask ( mm_modem_get_preferred_mode (ctx->modem)); - supported_modes_string = mm_modem_mode_build_string_from_mask ( - mm_modem_get_supported_modes (ctx->modem)); supported_ip_families_string = mm_bearer_ip_family_build_string_from_mask ( mm_modem_get_supported_ip_families (ctx->modem)); @@ -310,6 +313,15 @@ print_modem_info (void) else prefixed_revision = NULL; + if (supported_modes_string) { + gchar *prefixed; + + prefixed = mmcli_prefix_newlines (" | ", + supported_modes_string); + g_free (supported_modes_string); + supported_modes_string = prefixed; + } + /* Get signal quality info */ signal_quality = mm_modem_get_signal_quality (ctx->modem, &signal_quality_recent); diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt index 358f613c..1d1704b4 100644 --- a/docs/reference/libmm-glib/libmm-glib-sections.txt +++ b/docs/reference/libmm-glib/libmm-glib-sections.txt @@ -73,6 +73,7 @@ mm_object_get_type <FILE>mm-modem</FILE> <TITLE>MMModem</TITLE> MMModem +MMModemModeCombination <SUBSECTION Getters> mm_modem_get_path mm_modem_dup_path @@ -106,6 +107,7 @@ mm_modem_get_max_bearers mm_modem_get_max_active_bearers mm_modem_get_own_numbers mm_modem_dup_own_numbers +mm_modem_peek_supported_modes mm_modem_get_supported_modes mm_modem_get_allowed_modes mm_modem_get_preferred_mode @@ -1455,6 +1457,7 @@ mm_gdbus_modem_get_supported_bands mm_gdbus_modem_dup_supported_bands mm_gdbus_modem_get_supported_ip_families mm_gdbus_modem_get_supported_modes +mm_gdbus_modem_dup_supported_modes mm_gdbus_modem_get_unlock_required mm_gdbus_modem_get_unlock_retries mm_gdbus_modem_dup_unlock_retries diff --git a/introspection/org.freedesktop.ModemManager1.Modem.xml b/introspection/org.freedesktop.ModemManager1.Modem.xml index 0f8364b7..7b43846e 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.xml @@ -410,14 +410,25 @@ <!-- SupportedModes: - Bitmask of <link linkend="MMModemMode">MMModemMode</link> values, - specifying the access technologies supported by the device. + This property exposes the supported mode combinations, given as an array of unsigned + integer pairs, where: - For POTS devices, only the - <link linkend="MM-MODEM-MODE-ANY:CAPS"><constant>MM_MODEM_MODE_ANY</constant></link> - mode will be returned. + <variablelist> + <varlistentry> + <listitem> + The first integer is a bitmask of <link linkend="MMModemMode">MMModemMode</link> values, + specifying the allowed modes. + </listitem> + </varlistentry> + <varlistentry> + <listitem> + The second integer is a single <link linkend="MMModemMode">MMModemMode</link>, which + specifies the preferred access technology, among the ones defined in the allowed modes. + </listitem> + </varlistentry> + </variablelist> --> - <property name="SupportedModes" type="u" access="read" /> + <property name="SupportedModes" type="a(uu)" access="read" /> <!-- AllowedModes: diff --git a/libmm-glib/Makefile.am b/libmm-glib/Makefile.am index b0a83e0e..b189b913 100644 --- a/libmm-glib/Makefile.am +++ b/libmm-glib/Makefile.am @@ -5,6 +5,7 @@ lib_LTLIBRARIES = libmm-glib.la libmm_glib_la_SOURCES = \ libmm-glib.h \ mm-helpers.h \ + mm-helper-types.h \ mm-manager.h \ mm-manager.c \ mm-object.h \ @@ -77,6 +78,7 @@ libmm_glib_la_LIBADD = \ includedir = @includedir@/libmm-glib include_HEADERS = \ libmm-glib.h \ + mm-helper-types.h \ mm-manager.h \ mm-object.h \ mm-modem.h \ diff --git a/libmm-glib/libmm-glib.h b/libmm-glib/libmm-glib.h index 468a3856..8b5e9200 100644 --- a/libmm-glib/libmm-glib.h +++ b/libmm-glib/libmm-glib.h @@ -52,6 +52,7 @@ # include <mm-common-helpers.h> #endif +#include <mm-helper-types.h> #include <mm-simple-status.h> #include <mm-simple-connect-properties.h> #include <mm-sms-properties.h> diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c index aabc070c..2b158354 100644 --- a/libmm-glib/mm-common-helpers.c +++ b/libmm-glib/mm-common-helpers.c @@ -73,6 +73,38 @@ mm_common_build_sms_storages_string (const MMSmsStorage *storages, return g_string_free (str, FALSE); } +gchar * +mm_common_build_mode_combinations_string (const MMModemModeCombination *modes, + guint n_modes) +{ + gboolean first = TRUE; + GString *str; + guint i; + + if (!modes || !n_modes) + return g_strdup ("none"); + + str = g_string_new (""); + for (i = 0; i < n_modes; i++) { + gchar *allowed; + gchar *preferred; + + allowed = mm_modem_mode_build_string_from_mask (modes[i].allowed); + preferred = mm_modem_mode_build_string_from_mask (modes[i].preferred); + g_string_append_printf (str, "%sallowed: %s; preferred: %s", + first ? "" : "\n", + allowed, + preferred); + g_free (allowed); + g_free (preferred); + + if (first) + first = FALSE; + } + + return g_string_free (str, FALSE); +} + GArray * mm_common_sms_storages_variant_to_garray (GVariant *variant) { @@ -357,6 +389,96 @@ mm_common_bands_garray_cmp (GArray *a, GArray *b) return !different; } +GArray * +mm_common_mode_combinations_variant_to_garray (GVariant *variant) +{ + GArray *array = NULL; + + if (variant) { + GVariantIter iter; + guint n; + + g_variant_iter_init (&iter, variant); + n = g_variant_iter_n_children (&iter); + + if (n > 0) { + MMModemModeCombination mode; + + array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), n); + while (g_variant_iter_loop (&iter, "(uu)", &mode.allowed, &mode.preferred)) + g_array_append_val (array, mode); + } + } + + /* If nothing set, fallback to default */ + if (!array) { + MMModemModeCombination default_mode; + + default_mode.allowed = MM_MODEM_MODE_ANY; + default_mode.preferred = MM_MODEM_MODE_NONE; + array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1); + g_array_append_val (array, default_mode); + } + + return array; +} + +MMModemModeCombination * +mm_common_mode_combinations_variant_to_array (GVariant *variant, + guint *n_modes) +{ + GArray *array; + + array = mm_common_mode_combinations_variant_to_garray (variant); + if (n_modes) + *n_modes = array->len; + return (MMModemModeCombination *) g_array_free (array, FALSE); +} + +GVariant * +mm_common_mode_combinations_array_to_variant (const MMModemModeCombination *modes, + guint n_modes) +{ + if (n_modes > 0) { + GVariantBuilder builder; + guint i; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(uu)")); + + for (i = 0; i < n_modes; i++) + g_variant_builder_add_value (&builder, + g_variant_new ("(uu)", + ((guint32)modes[i].allowed), + ((guint32)modes[i].preferred))); + return g_variant_builder_end (&builder); + } + + return mm_common_build_mode_combinations_default (); +} + +GVariant * +mm_common_mode_combinations_garray_to_variant (GArray *array) +{ + if (array) + return mm_common_mode_combinations_array_to_variant ((const MMModemModeCombination *)array->data, + array->len); + + return mm_common_mode_combinations_array_to_variant (NULL, 0); +} + +GVariant * +mm_common_build_mode_combinations_default (void) +{ + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(uu)")); + g_variant_builder_add_value (&builder, + g_variant_new ("(uu)", + MM_MODEM_MODE_ANY, + MM_MODEM_MODE_NONE)); + return g_variant_builder_end (&builder); +} + gboolean mm_common_get_boolean_from_string (const gchar *value, GError **error) diff --git a/libmm-glib/mm-common-helpers.h b/libmm-glib/mm-common-helpers.h index d23fc73e..45df4f4c 100644 --- a/libmm-glib/mm-common-helpers.h +++ b/libmm-glib/mm-common-helpers.h @@ -17,6 +17,7 @@ #include <glib.h> #include <ModemManager.h> +#include "mm-helper-types.h" #if !defined (__LIBMM_GLIB_H_INSIDE__) && !defined (LIBMM_GLIB_COMPILATION) #error "Only <libmm-glib.h> can be included directly." @@ -31,6 +32,9 @@ gchar *mm_common_build_bands_string (const MMModemBand *bands, gchar *mm_common_build_sms_storages_string (const MMSmsStorage *storages, guint n_storages); +gchar *mm_common_build_mode_combinations_string (const MMModemModeCombination *modes, + guint n_modes); + MMModemMode mm_common_get_modes_from_string (const gchar *str, GError **error); void mm_common_get_bands_from_string (const gchar *str, @@ -67,6 +71,14 @@ GVariant *mm_common_build_bands_unknown (void); gboolean mm_common_bands_garray_cmp (GArray *a, GArray *b); +GArray *mm_common_mode_combinations_variant_to_garray (GVariant *variant); +MMModemModeCombination *mm_common_mode_combinations_variant_to_array (GVariant *variant, + guint *n_modes); +GVariant *mm_common_mode_combinations_array_to_variant (const MMModemModeCombination *modes, + guint n_modes); +GVariant *mm_common_mode_combinations_garray_to_variant (GArray *array); +GVariant *mm_common_build_mode_combinations_default (void); + typedef gboolean (*MMParseKeyValueForeachFn) (const gchar *key, const gchar *value, gpointer user_data); diff --git a/libmm-glib/mm-helper-types.h b/libmm-glib/mm-helper-types.h new file mode 100644 index 00000000..129b01d4 --- /dev/null +++ b/libmm-glib/mm-helper-types.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * libmm -- Access modem status & information from glib applications + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org> + */ + +#include <ModemManager.h> + +#if !defined (__LIBMM_GLIB_H_INSIDE__) && !defined (LIBMM_GLIB_COMPILATION) +#error "Only <libmm-glib.h> can be included directly." +#endif + +#ifndef _MM_HELPER_TYPES_H_ +#define _MM_HELPER_TYPES_H_ + +/** + * MMModemModeCombination: + * @allowed: Mask of #MMModemMode values specifying allowed modes. + * @preferred: A single #MMModemMode value specifying the preferred mode. + * + * #MMModemModeCombination is a simple struct holding a pair of #MMModemMode values. + */ +typedef struct _MMModemModeCombination { + MMModemMode allowed; + MMModemMode preferred; +} MMModemModeCombination; + +#endif /* _MM_HELPER_TYPES_H_ */ diff --git a/libmm-glib/mm-modem.c b/libmm-glib/mm-modem.c index af0f9fe1..2f916f5b 100644 --- a/libmm-glib/mm-modem.c +++ b/libmm-glib/mm-modem.c @@ -49,6 +49,11 @@ struct _MMModemPrivate { guint unlock_retries_id; MMUnlockRetries *unlock_retries; + /* Supported Modes */ + GMutex supported_modes_mutex; + guint supported_modes_id; + GArray *supported_modes; + /* Supported Bands */ GMutex supported_bands_mutex; guint supported_bands_id; @@ -910,22 +915,120 @@ mm_modem_get_signal_quality (MMModem *self, /*****************************************************************************/ +static void +supported_modes_updated (MMModem *self, + GParamSpec *pspec) +{ + g_mutex_lock (&self->priv->supported_modes_mutex); + { + GVariant *dictionary; + + if (self->priv->supported_modes) + g_array_unref (self->priv->supported_modes); + + dictionary = mm_gdbus_modem_get_supported_modes (MM_GDBUS_MODEM (self)); + self->priv->supported_modes = (dictionary ? + mm_common_mode_combinations_variant_to_garray (dictionary) : + NULL); + } + g_mutex_unlock (&self->priv->supported_modes_mutex); +} + +static gboolean +ensure_internal_supported_modes (MMModem *self, + MMModemModeCombination **dup_modes, + guint *dup_modes_n) +{ + gboolean ret; + + g_mutex_lock (&self->priv->supported_modes_mutex); + { + /* If this is the first time ever asking for the array, setup the + * update listener and the initial array, if any. */ + if (!self->priv->supported_modes_id) { + GVariant *dictionary; + + dictionary = mm_gdbus_modem_dup_supported_modes (MM_GDBUS_MODEM (self)); + if (dictionary) { + self->priv->supported_modes = mm_common_mode_combinations_variant_to_garray (dictionary); + g_variant_unref (dictionary); + } + + /* No need to clear this signal connection when freeing self */ + self->priv->supported_modes_id = + g_signal_connect (self, + "notify::supported-modes", + G_CALLBACK (supported_modes_updated), + NULL); + } + + if (!self->priv->supported_modes) + ret = FALSE; + else { + ret = TRUE; + + if (dup_modes && dup_modes_n) { + *dup_modes_n = self->priv->supported_modes->len; + if (self->priv->supported_modes->len > 0) { + *dup_modes = g_malloc (sizeof (MMModemModeCombination) * self->priv->supported_modes->len); + memcpy (*dup_modes, self->priv->supported_modes->data, sizeof (MMModemModeCombination) * self->priv->supported_modes->len); + } else + *dup_modes = NULL; + } + } + } + g_mutex_unlock (&self->priv->supported_modes_mutex); + + return ret; +} + /** * mm_modem_get_supported_modes: * @self: A #MMModem. + * @modes: (out) (array length=n_modes): Return location for the array of #MMModemModeCombination structs. The returned array should be freed with g_free() when no longer needed. + * @n_modes: (out): Return location for the number of values in @modes. * - * Gets the list of modes specifying the access technologies supported by the #MMModem. + * Gets the list of supported mode combinations. + * + * Returns: %TRUE if @modes and @n_modes are set, %FALSE otherwise. + */ +gboolean +mm_modem_get_supported_modes (MMModem *self, + MMModemModeCombination **modes, + guint *n_modes) +{ + g_return_val_if_fail (MM_IS_MODEM (self), FALSE); + g_return_val_if_fail (modes != NULL, FALSE); + g_return_val_if_fail (n_modes != NULL, FALSE); + + return ensure_internal_supported_modes (self, modes, n_modes); +} + +/** + * mm_modem_peek_supported_modes: + * @self: A #MMModem. + * @modes: (out) (array length=n_modes): Return location for the array of #MMModemModeCombination values. Do not free the returned array, it is owned by @self. + * @n_modes: (out): Return location for the number of values in @modes. * - * For POTS devices, only #MM_MODEM_MODE_ANY will be returned. + * Gets the list of supported mode combinations. * - * Returns: A bitmask of #MMModemMode values. + * Returns: %TRUE if @modes and @n_modes are set, %FALSE otherwise. */ -MMModemMode -mm_modem_get_supported_modes (MMModem *self) +gboolean +mm_modem_peek_supported_modes (MMModem *self, + const MMModemModeCombination **modes, + guint *n_modes) { - g_return_val_if_fail (MM_IS_MODEM (self), MM_MODEM_MODE_NONE); + g_return_val_if_fail (MM_IS_MODEM (self), FALSE); + g_return_val_if_fail (modes != NULL, FALSE); + g_return_val_if_fail (n_modes != NULL, FALSE); - return (MMModemMode) mm_gdbus_modem_get_supported_modes (MM_GDBUS_MODEM (self)); + if (!ensure_internal_supported_modes (self, NULL, NULL)) + return FALSE; + + *n_modes = self->priv->supported_modes->len; + *modes = (MMModemModeCombination *)self->priv->supported_modes->data; + return TRUE; } /*****************************************************************************/ @@ -2533,6 +2636,7 @@ mm_modem_init (MMModem *self) MM_TYPE_MODEM, MMModemPrivate); g_mutex_init (&self->priv->unlock_retries_mutex); + g_mutex_init (&self->priv->supported_modes_mutex); g_mutex_init (&self->priv->supported_bands_mutex); g_mutex_init (&self->priv->current_bands_mutex); } @@ -2543,9 +2647,12 @@ finalize (GObject *object) MMModem *self = MM_MODEM (object); g_mutex_clear (&self->priv->unlock_retries_mutex); + g_mutex_clear (&self->priv->supported_modes_mutex); g_mutex_clear (&self->priv->supported_bands_mutex); g_mutex_clear (&self->priv->current_bands_mutex); + if (self->priv->supported_modes) + g_array_unref (self->priv->supported_modes); if (self->priv->supported_bands) g_array_unref (self->priv->supported_bands); if (self->priv->current_bands) diff --git a/libmm-glib/mm-modem.h b/libmm-glib/mm-modem.h index 2ba6d82e..aeabb84f 100644 --- a/libmm-glib/mm-modem.h +++ b/libmm-glib/mm-modem.h @@ -34,6 +34,7 @@ #include "mm-unlock-retries.h" #include "mm-sim.h" #include "mm-bearer.h" +#include "mm-helper-types.h" G_BEGIN_DECLS @@ -127,7 +128,12 @@ MMModemAccessTechnology mm_modem_get_access_technologies (MMModem *self); guint mm_modem_get_signal_quality (MMModem *self, gboolean *recent); -MMModemMode mm_modem_get_supported_modes (MMModem *self); +gboolean mm_modem_peek_supported_modes (MMModem *self, + const MMModemModeCombination **modes, + guint *n_modes); +gboolean mm_modem_get_supported_modes (MMModem *self, + MMModemModeCombination **modes, + guint *n_modes); MMModemMode mm_modem_get_allowed_modes (MMModem *self); diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c index 921755ba..4c74774c 100644 --- a/plugins/cinterion/mm-broadband-modem-cinterion.c +++ b/plugins/cinterion/mm-broadband-modem-cinterion.c @@ -38,10 +38,12 @@ static void iface_modem_init (MMIfaceModem *iface); static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); static void iface_modem_messaging_init (MMIfaceModemMessaging *iface); +static MMIfaceModem *iface_modem_parent; + G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion, MM_TYPE_BROADBAND_MODEM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)) struct _MMBroadbandModemCinterionPrivate { /* Flag to know if we should try AT^SIND or not to get psinfo */ @@ -514,6 +516,80 @@ load_access_technologies (MMIfaceModem *self, } /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list of combinations */ + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); + + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* ALLOWED MODES */ static gboolean @@ -1191,6 +1267,10 @@ finalize (GObject *object) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->set_allowed_modes = set_allowed_modes; iface->set_allowed_modes_finish = set_allowed_modes_finish; iface->load_supported_bands = load_supported_bands; diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c index 19965b47..410032df 100644 --- a/plugins/huawei/mm-broadband-modem-huawei.c +++ b/plugins/huawei/mm-broadband-modem-huawei.c @@ -1075,6 +1075,90 @@ set_current_bands (MMIfaceModem *self, } /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list 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); + /* CDMA modems don't support 'preferred' setups */ + if (!mm_iface_modem_is_cdma_only (self)) { + /* 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); + } + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ static gboolean @@ -1091,7 +1175,7 @@ parse_prefmode (const gchar *response, MMModemMode *preferred, GError **error) *preferred = MM_MODEM_MODE_3G; return TRUE; } else if (a == 8) { - *preferred = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G; + *preferred = MM_MODEM_MODE_NONE; return TRUE; } @@ -1116,10 +1200,7 @@ load_allowed_modes_finish (MMIfaceModem *self, return FALSE; if (mm_iface_modem_is_cdma_only (self)) { - /* CDMA-only devices always support 2G and 3G if they have 3G, so just - * use the modes from GCAP as the list of allowed modes. - */ - *allowed = mm_iface_modem_get_supported_modes (self); + *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); return parse_prefmode (response, preferred, error); } @@ -2660,6 +2741,8 @@ iface_modem_init (MMIfaceModem *iface) iface->load_current_bands_finish = load_current_bands_finish; iface->set_current_bands = set_current_bands; iface->set_current_bands_finish = set_current_bands_finish; + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/icera/mm-broadband-modem-icera.c b/plugins/icera/mm-broadband-modem-icera.c index 7d8661bc..a9fdfe38 100644 --- a/plugins/icera/mm-broadband-modem-icera.c +++ b/plugins/icera/mm-broadband-modem-icera.c @@ -40,12 +40,13 @@ static void iface_modem_init (MMIfaceModem *iface); static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); static void iface_modem_time_init (MMIfaceModemTime *iface); +static MMIfaceModem *iface_modem_parent; static MMIfaceModem3gpp *iface_modem_3gpp_parent; G_DEFINE_TYPE_EXTENDED (MMBroadbandModemIcera, mm_broadband_modem_icera, MM_TYPE_BROADBAND_MODEM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)) enum { PROP_0, @@ -67,6 +68,88 @@ struct _MMBroadbandModemIceraPrivate { }; /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list 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); + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ static gboolean @@ -201,7 +284,8 @@ modem_set_allowed_modes (MMIfaceModem *self, icera_mode = 3; else /* none preferred, so AUTO */ icera_mode = 5; - } + } else if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE) + icera_mode = 5; if (icera_mode < 0) { gchar *allowed_str; @@ -1769,6 +1853,10 @@ finalize (GObject *object) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = modem_load_allowed_modes; iface->load_allowed_modes_finish = modem_load_allowed_modes_finish; iface->set_allowed_modes = modem_set_allowed_modes; diff --git a/plugins/iridium/mm-broadband-modem-iridium.c b/plugins/iridium/mm-broadband-modem-iridium.c index c3c81aaf..b26851b2 100644 --- a/plugins/iridium/mm-broadband-modem-iridium.c +++ b/plugins/iridium/mm-broadband-modem-iridium.c @@ -219,13 +219,12 @@ setup_flow_control (MMIfaceModem *self, /*****************************************************************************/ /* Load supported modes (Modem inteface) */ -static MMModemMode +static GArray * load_supported_modes_finish (MMIfaceModem *self, GAsyncResult *res, GError **error) { - /* Report CS only, Iridium connections are circuit-switched */ - return MM_MODEM_MODE_CS; + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); } static void @@ -234,11 +233,23 @@ load_supported_modes (MMIfaceModem *self, gpointer user_data) { GSimpleAsyncResult *result; + GArray *combinations; + MMModemModeCombination mode; result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, load_supported_modes); + + /* Build list of combinations */ + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1); + + /* Report CS only, Iridium connections are circuit-switched */ + mode.allowed = MM_MODEM_MODE_CS; + mode.preferred = MM_MODEM_MODE_NONE; + g_array_append_val (combinations, mode); + + 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/plugins/linktop/mm-broadband-modem-linktop.c b/plugins/linktop/mm-broadband-modem-linktop.c index 49722819..bcfa7daf 100644 --- a/plugins/linktop/mm-broadband-modem-linktop.c +++ b/plugins/linktop/mm-broadband-modem-linktop.c @@ -40,8 +40,84 @@ static void iface_modem_init (MMIfaceModem *iface); +static MMIfaceModem *iface_modem_parent; + G_DEFINE_TYPE_EXTENDED (MMBroadbandModemLinktop, mm_broadband_modem_linktop, MM_TYPE_BROADBAND_MODEM, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)) + +/*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list of combinations */ + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); + + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} /*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ @@ -158,9 +234,11 @@ set_allowed_modes (MMIfaceModem *self, else if (allowed == MM_MODEM_MODE_3G) linktop_mode = LINKTOP_MODE_3G; else if ((allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) && - (preferred == MM_MODEM_MODE_NONE)) { + (preferred == MM_MODEM_MODE_NONE)) + linktop_mode = LINKTOP_MODE_ANY; + else if ((allowed == MM_MODEM_MODE_ANY && + preferred == MM_MODEM_MODE_NONE)) linktop_mode = LINKTOP_MODE_ANY; - } if (linktop_mode < 0) { gchar *allowed_str; @@ -220,6 +298,10 @@ mm_broadband_modem_linktop_init (MMBroadbandModemLinktop *self) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/longcheer/mm-broadband-modem-longcheer.c b/plugins/longcheer/mm-broadband-modem-longcheer.c index 949d54d8..3abaaeaf 100644 --- a/plugins/longcheer/mm-broadband-modem-longcheer.c +++ b/plugins/longcheer/mm-broadband-modem-longcheer.c @@ -33,8 +33,88 @@ static void iface_modem_init (MMIfaceModem *iface); +static MMIfaceModem *iface_modem_parent; + G_DEFINE_TYPE_EXTENDED (MMBroadbandModemLongcheer, mm_broadband_modem_longcheer, MM_TYPE_BROADBAND_MODEM, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)) + +/*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list of combinations */ + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 4); + + /* 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, 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} /*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ @@ -76,16 +156,16 @@ load_allowed_modes_finish (MMIfaceModem *self, *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); *preferred = MM_MODEM_MODE_3G; return TRUE; - case 4: - /* GSM preferred */ - *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - *preferred = MM_MODEM_MODE_2G; - return TRUE; case 3: /* GSM only */ *allowed = MM_MODEM_MODE_2G; *preferred = MM_MODEM_MODE_NONE; return TRUE; + case 4: + /* GSM preferred */ + *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); + *preferred = MM_MODEM_MODE_2G; + return TRUE; default: break; } @@ -159,14 +239,14 @@ set_allowed_modes (MMIfaceModem *self, mododr = 3; else if (allowed == MM_MODEM_MODE_3G) mododr = 1; - else if (allowed == MM_MODEM_MODE_ANY || (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G))) { + else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) { if (preferred == MM_MODEM_MODE_2G) mododr = 4; - else if (preferred == MM_MODEM_MODE_3G || - preferred == MM_MODEM_MODE_NONE || - preferred == MM_MODEM_MODE_ANY) + else if (preferred == MM_MODEM_MODE_3G) mododr = 2; - } + } else if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE) + /* Default to 3G preferred */ + mododr = 2; if (mododr == 0) { gchar *allowed_str; @@ -338,8 +418,12 @@ mm_broadband_modem_longcheer_init (MMBroadbandModemLongcheer *self) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + iface->load_access_technologies = load_access_technologies; iface->load_access_technologies_finish = load_access_technologies_finish; + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/mbm/mm-broadband-modem-mbm.c b/plugins/mbm/mm-broadband-modem-mbm.c index f75a9a8d..e5eacaf0 100644 --- a/plugins/mbm/mm-broadband-modem-mbm.c +++ b/plugins/mbm/mm-broadband-modem-mbm.c @@ -45,6 +45,7 @@ static void iface_modem_init (MMIfaceModem *iface); static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); +static MMIfaceModem *iface_modem_parent; static MMIfaceModem3gpp *iface_modem_3gpp_parent; G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbm, mm_broadband_modem_mbm, MM_TYPE_BROADBAND_MODEM, 0, @@ -191,6 +192,80 @@ modem_after_sim_unlock (MMIfaceModem *self, } /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list of combinations */ + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); + + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ static gboolean @@ -1237,12 +1312,16 @@ finalize (GObject *object) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + iface->create_bearer = modem_create_bearer; iface->create_bearer_finish = modem_create_bearer_finish; iface->create_sim = create_sim; iface->create_sim_finish = create_sim_finish; iface->modem_after_sim_unlock = modem_after_sim_unlock; iface->modem_after_sim_unlock_finish = modem_after_sim_unlock_finish; + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/nokia/mm-broadband-modem-nokia.c b/plugins/nokia/mm-broadband-modem-nokia.c index 998683c1..a0f870b8 100644 --- a/plugins/nokia/mm-broadband-modem-nokia.c +++ b/plugins/nokia/mm-broadband-modem-nokia.c @@ -68,45 +68,6 @@ create_sim (MMIfaceModem *self, } /*****************************************************************************/ -/* Load supported modes (Modem interface) */ - -static MMModemMode -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))); -} - -static void -modem_load_supported_modes (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *result; - MMModemMode mode; - - /* Nokia phones don't seem to like AT+WS46?, they just report 2G even if - * 3G is supported, so we'll just assume they actually do 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; - - 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); - g_simple_async_result_complete_in_idle (result); - g_object_unref (result); -} - -/*****************************************************************************/ /* Load access technologies (Modem interface) */ typedef struct { @@ -407,8 +368,6 @@ iface_modem_init (MMIfaceModem *iface) iface->modem_power_down = NULL; iface->modem_power_down_finish = NULL; - iface->load_supported_modes = modem_load_supported_modes; - iface->load_supported_modes_finish = modem_load_supported_modes_finish; iface->load_access_technologies = load_access_technologies; iface->load_access_technologies_finish = load_access_technologies_finish; } diff --git a/plugins/novatel/mm-broadband-modem-novatel.c b/plugins/novatel/mm-broadband-modem-novatel.c index 3d84509b..62f4a3a7 100644 --- a/plugins/novatel/mm-broadband-modem-novatel.c +++ b/plugins/novatel/mm-broadband-modem-novatel.c @@ -48,7 +48,89 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemNovatel, mm_broadband_modem_novatel, MM_ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)) + +/*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list 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); + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} /*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ @@ -275,6 +357,10 @@ set_allowed_modes (MMIfaceModem *self, a = 1; else if (preferred == MM_MODEM_MODE_3G) a = 2; + } else if (allowed == MM_MODEM_MODE_ANY && + preferred == MM_MODEM_MODE_NONE) { + b = 2; + a = 0; } if (a < 0 || b < 0) { @@ -1149,6 +1235,8 @@ iface_modem_init (MMIfaceModem *iface) { iface_modem_parent = g_type_interface_peek_parent (iface); + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/option/mm-broadband-modem-option.c b/plugins/option/mm-broadband-modem-option.c index 4c63f3db..42d9570e 100644 --- a/plugins/option/mm-broadband-modem-option.c +++ b/plugins/option/mm-broadband-modem-option.c @@ -35,11 +35,12 @@ static void iface_modem_init (MMIfaceModem *iface); static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); +static MMIfaceModem *iface_modem_parent; static MMIfaceModem3gpp *iface_modem_3gpp_parent; G_DEFINE_TYPE_EXTENDED (MMBroadbandModemOption, mm_broadband_modem_option, MM_TYPE_BROADBAND_MODEM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)) struct _MMBroadbandModemOptionPrivate { /* Regex for access-technology related notifications */ @@ -57,6 +58,88 @@ struct _MMBroadbandModemOptionPrivate { }; /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list 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); + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ static gboolean @@ -186,7 +269,8 @@ set_allowed_modes (MMIfaceModem *self, option_mode = 3; else /* none preferred, so AUTO */ option_mode = 5; - } + } else if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE) + option_mode = 5; if (option_mode < 0) { gchar *allowed_str; @@ -1140,10 +1224,14 @@ mm_broadband_modem_option_init (MMBroadbandModemOption *self) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + iface->modem_after_power_up = modem_after_power_up; iface->modem_after_power_up_finish = modem_after_power_up_finish; iface->load_access_technologies = load_access_technologies; iface->load_access_technologies_finish = load_access_technologies_finish; + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/sierra/mm-broadband-modem-sierra.c b/plugins/sierra/mm-broadband-modem-sierra.c index f8cfb743..46d2f3c3 100644 --- a/plugins/sierra/mm-broadband-modem-sierra.c +++ b/plugins/sierra/mm-broadband-modem-sierra.c @@ -514,6 +514,109 @@ load_access_technologies (MMIfaceModem *self, } /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* CDMA-only modems don't support changing modes, default to parent's */ + if (!mm_iface_modem_is_3gpp (self)) { + g_simple_async_result_set_op_res_gpointer (simple, all, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete_in_idle (simple); + g_object_unref (simple); + return; + } + + /* Build list of combinations for 3GPP devices */ + 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); + + /* Non-LTE devices allow 2G/3G preferred modes */ + if (!mm_iface_modem_is_3gpp_lte (self)) { + /* 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); + } else { + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ typedef struct { @@ -569,7 +672,10 @@ selrat_query_ready (MMBaseModem *self, if (mm_get_uint_from_match_info (match_info, 1, &mode) && mode <= 7) { switch (mode) { case 0: - result.allowed = MM_MODEM_MODE_ANY; + result.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); + result.preferred = MM_MODEM_MODE_NONE; + if (mm_iface_modem_is_3gpp_lte (MM_IFACE_MODEM (self))) + result.allowed |= MM_MODEM_MODE_4G; result.preferred = MM_MODEM_MODE_NONE; break; case 1: @@ -583,7 +689,7 @@ selrat_query_ready (MMBaseModem *self, case 3: /* in Sierra LTE devices, mode 3 is automatic, including LTE, no preference */ if (mm_iface_modem_is_3gpp_lte (MM_IFACE_MODEM (self))) { - result.allowed = MM_MODEM_MODE_ANY; + result.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); result.preferred = MM_MODEM_MODE_NONE; } else { result.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); @@ -593,7 +699,7 @@ selrat_query_ready (MMBaseModem *self, case 4: /* in Sierra LTE devices, mode 4 is automatic, including LTE, no preference */ if (mm_iface_modem_is_3gpp_lte (MM_IFACE_MODEM (self))) { - result.allowed = MM_MODEM_MODE_ANY; + result.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); result.preferred = MM_MODEM_MODE_NONE; } else { result.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); @@ -773,9 +879,10 @@ set_allowed_modes (MMIfaceModem *self, idx = 0; } else if (allowed == MM_MODEM_MODE_4G) idx = 6; - else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G)) + else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G) && + preferred == MM_MODEM_MODE_NONE) idx = 7; - else if (allowed == MM_MODEM_MODE_ANY) + else if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE) idx = 0; if (idx < 0) { @@ -1556,6 +1663,8 @@ iface_modem_init (MMIfaceModem *iface) mm_common_sierra_peek_parent_interfaces (iface); + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/simtech/mm-broadband-modem-simtech.c b/plugins/simtech/mm-broadband-modem-simtech.c index 359dde50..f7353d88 100644 --- a/plugins/simtech/mm-broadband-modem-simtech.c +++ b/plugins/simtech/mm-broadband-modem-simtech.c @@ -37,11 +37,12 @@ static void iface_modem_init (MMIfaceModem *iface); static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); +static MMIfaceModem *iface_modem_parent; static MMIfaceModem3gpp *iface_modem_3gpp_parent; G_DEFINE_TYPE_EXTENDED (MMBroadbandModemSimtech, mm_broadband_modem_simtech, MM_TYPE_BROADBAND_MODEM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)) /*****************************************************************************/ /* Setup/Cleanup unsolicited events (3GPP interface) */ @@ -445,6 +446,87 @@ load_access_technologies (MMIfaceModem *self, } /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list 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); + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ typedef struct { @@ -731,19 +813,28 @@ set_allowed_modes (MMIfaceModem *self, user_data, set_allowed_modes); - ctx->nmp = 2; /* automatic mode preference */ - ctx->naop = 0; /* automatic acquisition order */ + /* Defaults: automatic search */ + ctx->nmp = 2; + ctx->naop = 0; - if (allowed == MM_MODEM_MODE_2G) + if (allowed == MM_MODEM_MODE_ANY && + preferred == MM_MODEM_MODE_NONE) { + /* defaults nmp and naop */ + } else if (allowed == MM_MODEM_MODE_2G) { ctx->nmp = 13; - else if (allowed == MM_MODEM_MODE_3G) + ctx->naop = 0; + } else if (allowed == MM_MODEM_MODE_3G) { ctx->nmp = 14; - else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) { + ctx->naop = 0; + } else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) { + /* default nmp */ if (preferred == MM_MODEM_MODE_2G) ctx->naop = 3; else if (preferred == MM_MODEM_MODE_3G) ctx->naop = 2; - /* else, auto */ + else + /* default naop */ + ctx->naop = 0; } else { gchar *allowed_str; gchar *preferred_str; @@ -830,8 +921,12 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + iface->load_access_technologies = load_access_technologies; iface->load_access_technologies_finish = load_access_technologies_finish; + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/wavecom/mm-broadband-modem-wavecom.c b/plugins/wavecom/mm-broadband-modem-wavecom.c index 6f487b42..1ee16e99 100644 --- a/plugins/wavecom/mm-broadband-modem-wavecom.c +++ b/plugins/wavecom/mm-broadband-modem-wavecom.c @@ -37,6 +37,8 @@ static void iface_modem_init (MMIfaceModem *iface); +static MMIfaceModem *iface_modem_parent; + G_DEFINE_TYPE_EXTENDED (MMBroadbandModemWavecom, mm_broadband_modem_wavecom, MM_TYPE_BROADBAND_MODEM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)) @@ -82,18 +84,17 @@ static const WavecomBand3G bands_3g[] = { }; /*****************************************************************************/ -/* Supported modes (Modem interface) */ +/* Load supported modes (Modem interface) */ -static MMModemMode +static GArray * load_supported_modes_finish (MMIfaceModem *self, GAsyncResult *res, GError **error) { if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) - return MM_MODEM_MODE_NONE; + return NULL; - 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 @@ -101,9 +102,13 @@ supported_ms_classes_query_ready (MMBaseModem *self, GAsyncResult *res, GSimpleAsyncResult *simple) { + GArray *all; + GArray *combinations; + GArray *filtered; const gchar *response; GError *error = NULL; - MMModemMode mode; + MMModemModeCombination mode; + MMModemMode mode_all; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) { @@ -115,40 +120,71 @@ supported_ms_classes_query_ready (MMBaseModem *self, } response = mm_strip_tag (response, "+CGCLASS:"); - mode = MM_MODEM_MODE_NONE; - - if (strstr (response, WAVECOM_MS_CLASS_A_IDSTR)) { - mm_dbg ("Modem supports Class A mobile station"); - mode |= MM_MODEM_MODE_3G; - } - - if (strstr (response, WAVECOM_MS_CLASS_B_IDSTR)) { - mm_dbg ("Modem supports Class B mobile station"); - mode |= (MM_MODEM_MODE_2G | MM_MODEM_MODE_CS); - } - - if (strstr (response, WAVECOM_MS_CLASS_CG_IDSTR)) { - mm_dbg ("Modem supports Class CG mobile station"); - mode |= MM_MODEM_MODE_2G; - } - - if (strstr (response, WAVECOM_MS_CLASS_CC_IDSTR)) { - mm_dbg ("Modem supports Class CC mobile station"); - mode |= MM_MODEM_MODE_CS; - } + mode_all = MM_MODEM_MODE_NONE; + if (strstr (response, WAVECOM_MS_CLASS_A_IDSTR)) + mode_all |= MM_MODEM_MODE_3G; + if (strstr (response, WAVECOM_MS_CLASS_B_IDSTR)) + mode_all |= (MM_MODEM_MODE_2G | MM_MODEM_MODE_CS); + if (strstr (response, WAVECOM_MS_CLASS_CG_IDSTR)) + mode_all |= MM_MODEM_MODE_2G; + if (strstr (response, WAVECOM_MS_CLASS_CC_IDSTR)) + mode_all |= MM_MODEM_MODE_CS; /* If none received, error */ - if (mode == MM_MODEM_MODE_NONE) + if (mode_all == MM_MODEM_MODE_NONE) { g_simple_async_result_set_error (simple, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't get supported mobile station classes: '%s'", response); - else - g_simple_async_result_set_op_res_gpointer (simple, - GUINT_TO_POINTER (mode), - NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + /* Build ALL mask */ + all = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1); + mode.allowed = mode_all; + mode.preferred = MM_MODEM_MODE_NONE; + g_array_append_val (all, mode); + + /* Build list of combinations */ + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 7); + /* CS only */ + mode.allowed = MM_MODEM_MODE_CS; + mode.preferred = MM_MODEM_MODE_NONE; + g_array_append_val (combinations, mode); + /* 2G only */ + mode.allowed = MM_MODEM_MODE_2G; + mode.preferred = MM_MODEM_MODE_NONE; + g_array_append_val (combinations, mode); + /* CS and 2G */ + mode.allowed = (MM_MODEM_MODE_CS | MM_MODEM_MODE_2G); + mode.preferred = MM_MODEM_MODE_2G; + 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); g_simple_async_result_complete (simple); g_object_unref (simple); } @@ -158,20 +194,16 @@ load_supported_modes (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *result; - - result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - load_supported_modes); - mm_base_modem_at_command ( MM_BASE_MODEM (self), "+CGCLASS=?", 3, FALSE, (GAsyncReadyCallback)supported_ms_classes_query_ready, - result); + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); } /*****************************************************************************/ @@ -387,8 +419,6 @@ load_allowed_modes (MMIfaceModem *self, typedef struct { MMBroadbandModemWavecom *self; GSimpleAsyncResult *result; - MMModemMode allowed; - MMModemMode preferred; gchar *cgclass_command; gchar *wwsm_command; } SetAllowedModesContext; @@ -473,19 +503,27 @@ set_allowed_modes (MMIfaceModem *self, callback, user_data, set_allowed_modes); - ctx->allowed = allowed; - ctx->preferred = preferred; + + /* Handle ANY/NONE */ + if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE) { + if (mm_iface_modem_is_3g (self)) { + allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); + preferred = MM_MODEM_MODE_NONE; + } else { + allowed = (MM_MODEM_MODE_CS | MM_MODEM_MODE_2G); + preferred = MM_MODEM_MODE_2G; + } + } if (allowed == MM_MODEM_MODE_CS) ctx->cgclass_command = g_strdup ("+CGCLASS=" WAVECOM_MS_CLASS_CC_IDSTR); else if (allowed == MM_MODEM_MODE_2G) ctx->cgclass_command = g_strdup ("+CGCLASS=" WAVECOM_MS_CLASS_CG_IDSTR); else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_CS) && - preferred == MM_MODEM_MODE_NONE) + preferred == MM_MODEM_MODE_2G) ctx->cgclass_command = g_strdup ("+CGCLASS=" WAVECOM_MS_CLASS_B_IDSTR); else if (allowed & MM_MODEM_MODE_3G) { - if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G) || - allowed == (MM_MODEM_MODE_CS | MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) { + if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) { if (preferred == MM_MODEM_MODE_2G) ctx->wwsm_command = g_strdup ("+WWSM=2,1"); else if (preferred == MM_MODEM_MODE_3G) @@ -1144,6 +1182,8 @@ mm_broadband_modem_wavecom_init (MMBroadbandModemWavecom *self) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + iface->load_supported_modes = load_supported_modes; iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; diff --git a/plugins/x22x/mm-broadband-modem-x22x.c b/plugins/x22x/mm-broadband-modem-x22x.c index 2120b6d2..3afb08cb 100644 --- a/plugins/x22x/mm-broadband-modem-x22x.c +++ b/plugins/x22x/mm-broadband-modem-x22x.c @@ -33,8 +33,83 @@ static void iface_modem_init (MMIfaceModem *iface); +static MMIfaceModem *iface_modem_parent; + G_DEFINE_TYPE_EXTENDED (MMBroadbandModemX22x, mm_broadband_modem_x22x, MM_TYPE_BROADBAND_MODEM, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)); + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)) + +/*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + /* Build list of combinations for 3GPP devices */ + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); + + /* 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); + + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} /*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ @@ -168,7 +243,8 @@ set_allowed_modes (MMIfaceModem *self, else if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE) syssel = 0; - else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) + else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G) && + preferred == MM_MODEM_MODE_NONE) syssel = 0; else { gchar *allowed_str; @@ -264,8 +340,12 @@ mm_broadband_modem_x22x_init (MMBroadbandModemX22x *self) static void iface_modem_init (MMIfaceModem *iface) { + iface_modem_parent = g_type_interface_peek_parent (iface); + iface->load_access_technologies = load_access_technologies; iface->load_access_technologies_finish = load_access_technologies_finish; + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; diff --git a/plugins/zte/mm-broadband-modem-zte.c b/plugins/zte/mm-broadband-modem-zte.c index e7d190ad..d4f4f0f8 100644 --- a/plugins/zte/mm-broadband-modem-zte.c +++ b/plugins/zte/mm-broadband-modem-zte.c @@ -250,6 +250,100 @@ modem_power_down (MMIfaceModem *self, } /*****************************************************************************/ +/* Load supported modes (Modem interface) */ + +static GArray * +load_supported_modes_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +parent_load_supported_modes_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + GArray *all; + GArray *combinations; + GArray *filtered; + MMModemModeCombination mode; + + all = iface_modem_parent->load_supported_modes_finish (self, res, &error); + if (!all) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Build list 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); + + if (!mm_iface_modem_is_3gpp_lte (self)) { + /* 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); + } else { + /* 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 (simple, filtered, (GDestroyNotify) g_array_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +load_supported_modes (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Run parent's loading */ + iface_modem_parent->load_supported_modes ( + MM_IFACE_MODEM (self), + (GAsyncReadyCallback)parent_load_supported_modes_ready, + g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_supported_modes)); +} + +/*****************************************************************************/ /* Load initial allowed/preferred modes (Modem interface) */ static gboolean @@ -413,7 +507,12 @@ set_allowed_modes (MMIfaceModem *self, pref_acq = 2; else /* none preferred, so AUTO */ pref_acq = 0; - } else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G)) { + } else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G) && + preferred == MM_MODEM_MODE_NONE) { + cm_mode = 0; + pref_acq = 0; + } else if (allowed == MM_MODEM_MODE_ANY && + preferred == MM_MODEM_MODE_NONE) { cm_mode = 0; pref_acq = 0; } else if (allowed == MM_MODEM_MODE_4G) { @@ -679,6 +778,8 @@ iface_modem_init (MMIfaceModem *iface) iface->modem_power_down_finish = modem_power_down_finish; iface->load_access_technologies = load_access_technologies; iface->load_access_technologies_finish = load_access_technologies_finish; + iface->load_supported_modes = load_supported_modes; + iface->load_supported_modes_finish = load_supported_modes_finish; iface->load_allowed_modes = load_allowed_modes; iface->load_allowed_modes_finish = load_allowed_modes_finish; iface->set_allowed_modes = set_allowed_modes; 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); |