aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/mmcli-modem.c24
-rw-r--r--docs/reference/libmm-glib/libmm-glib-sections.txt8
-rw-r--r--include/ModemManager-enums.h2
-rw-r--r--introspection/org.freedesktop.ModemManager1.Modem.xml16
-rw-r--r--libmm-glib/mm-common-helpers.c125
-rw-r--r--libmm-glib/mm-common-helpers.h12
-rw-r--r--libmm-glib/mm-modem.c122
-rw-r--r--libmm-glib/mm-modem.h7
-rw-r--r--src/mm-broadband-modem-mbim.c2
-rw-r--r--src/mm-broadband-modem-qmi.c94
-rw-r--r--src/mm-iface-modem.c78
-rw-r--r--src/mm-iface-modem.h14
-rw-r--r--src/mm-modem-helpers.c28
-rw-r--r--src/mm-modem-helpers.h3
-rw-r--r--src/tests/test-modem-helpers.c94
15 files changed, 540 insertions, 89 deletions
diff --git a/cli/mmcli-modem.c b/cli/mmcli-modem.c
index 188fab8a..7ab46244 100644
--- a/cli/mmcli-modem.c
+++ b/cli/mmcli-modem.c
@@ -235,7 +235,9 @@ print_modem_info (void)
{
gchar *drivers_string;
gchar *prefixed_revision;
- gchar *modem_capabilities_string;
+ gchar *supported_capabilities_string;
+ MMModemCapability *capabilities = NULL;
+ guint n_capabilities = 0;
gchar *current_capabilities_string;
gchar *access_technologies_string;
MMModemModeCombination *modes = NULL;
@@ -264,8 +266,9 @@ print_modem_info (void)
#define VALIDATE_PATH(str) ((str && !g_str_equal (str, "/")) ? str : "none")
/* Strings in heap */
- modem_capabilities_string = mm_modem_capability_build_string_from_mask (
- mm_modem_get_modem_capabilities (ctx->modem));
+ mm_modem_get_supported_capabilities (ctx->modem, &capabilities, &n_capabilities);
+ supported_capabilities_string = mm_common_build_capabilities_string (capabilities, n_capabilities);
+ g_free (capabilities);
current_capabilities_string = mm_modem_capability_build_string_from_mask (
mm_modem_get_current_capabilities (ctx->modem));
access_technologies_string = mm_modem_access_technology_build_string_from_mask (
@@ -324,6 +327,15 @@ print_modem_info (void)
supported_modes_string = prefixed;
}
+ if (supported_capabilities_string) {
+ gchar *prefixed;
+
+ prefixed = mmcli_prefix_newlines (" | ",
+ supported_capabilities_string);
+ g_free (supported_capabilities_string);
+ supported_capabilities_string = prefixed;
+ }
+
/* Get signal quality info */
signal_quality = mm_modem_get_signal_quality (ctx->modem, &signal_quality_recent);
@@ -338,13 +350,13 @@ print_modem_info (void)
" Hardware | manufacturer: '%s'\n"
" | model: '%s'\n"
" | revision: '%s'\n"
- " | capabilities: '%s'\n"
+ " | supported: '%s'\n"
" | current: '%s'\n"
" | equipment id: '%s'\n",
VALIDATE_UNKNOWN (mm_modem_get_manufacturer (ctx->modem)),
VALIDATE_UNKNOWN (mm_modem_get_model (ctx->modem)),
VALIDATE_UNKNOWN (prefixed_revision),
- VALIDATE_UNKNOWN (modem_capabilities_string),
+ VALIDATE_UNKNOWN (supported_capabilities_string),
VALIDATE_UNKNOWN (current_capabilities_string),
VALIDATE_UNKNOWN (mm_modem_get_equipment_identifier (ctx->modem)));
@@ -475,7 +487,7 @@ print_modem_info (void)
g_free (current_bands_string);
g_free (supported_bands_string);
g_free (access_technologies_string);
- g_free (modem_capabilities_string);
+ g_free (supported_capabilities_string);
g_free (current_capabilities_string);
g_free (prefixed_revision);
g_free (allowed_modes_string);
diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt
index 830186f3..4bc13686 100644
--- a/docs/reference/libmm-glib/libmm-glib-sections.txt
+++ b/docs/reference/libmm-glib/libmm-glib-sections.txt
@@ -80,7 +80,8 @@ mm_modem_dup_path
mm_modem_get_state
mm_modem_get_state_failed_reason
mm_modem_get_power_state
-mm_modem_get_modem_capabilities
+mm_modem_peek_supported_capabilities
+mm_modem_get_supported_capabilities
mm_modem_get_current_capabilities
mm_modem_get_manufacturer
mm_modem_dup_manufacturer
@@ -1436,7 +1437,6 @@ mm_gdbus_modem_get_max_active_bearers
mm_gdbus_modem_get_max_bearers
mm_gdbus_modem_get_model
mm_gdbus_modem_dup_model
-mm_gdbus_modem_get_modem_capabilities
mm_gdbus_modem_get_own_numbers
mm_gdbus_modem_dup_own_numbers
mm_gdbus_modem_get_plugin
@@ -1450,6 +1450,8 @@ mm_gdbus_modem_get_signal_quality
mm_gdbus_modem_dup_signal_quality
mm_gdbus_modem_get_sim
mm_gdbus_modem_dup_sim
+mm_gdbus_modem_get_supported_capabilities
+mm_gdbus_modem_dup_supported_capabilities
mm_gdbus_modem_get_state
mm_gdbus_modem_get_state_failed_reason
mm_gdbus_modem_get_supported_bands
@@ -1504,13 +1506,13 @@ mm_gdbus_modem_set_manufacturer
mm_gdbus_modem_set_max_active_bearers
mm_gdbus_modem_set_max_bearers
mm_gdbus_modem_set_model
-mm_gdbus_modem_set_modem_capabilities
mm_gdbus_modem_set_own_numbers
mm_gdbus_modem_set_plugin
mm_gdbus_modem_set_primary_port
mm_gdbus_modem_set_revision
mm_gdbus_modem_set_signal_quality
mm_gdbus_modem_set_sim
+mm_gdbus_modem_set_supported_capabilities
mm_gdbus_modem_set_state
mm_gdbus_modem_set_state_failed_reason
mm_gdbus_modem_set_power_state
diff --git a/include/ModemManager-enums.h b/include/ModemManager-enums.h
index a3c37e4b..b268925c 100644
--- a/include/ModemManager-enums.h
+++ b/include/ModemManager-enums.h
@@ -38,6 +38,7 @@
* @MM_MODEM_CAPABILITY_LTE: Modem has LTE data capability.
* @MM_MODEM_CAPABILITY_LTE_ADVANCED: Modem has LTE Advanced data capability.
* @MM_MODEM_CAPABILITY_IRIDIUM: Modem has Iridium capabilities.
+ * @MM_MODEM_CAPABILITY_ANY: Mask specifying all capabilities.
*
* Flags describing one or more of the general access technology families that a
* modem supports.
@@ -50,6 +51,7 @@ typedef enum { /*< underscore_name=mm_modem_capability >*/
MM_MODEM_CAPABILITY_LTE = 1 << 3,
MM_MODEM_CAPABILITY_LTE_ADVANCED = 1 << 4,
MM_MODEM_CAPABILITY_IRIDIUM = 1 << 5,
+ MM_MODEM_CAPABILITY_ANY = 0xFFFFFFFF
} MMModemCapability;
/**
diff --git a/introspection/org.freedesktop.ModemManager1.Modem.xml b/introspection/org.freedesktop.ModemManager1.Modem.xml
index ba540ac8..46fa97dd 100644
--- a/introspection/org.freedesktop.ModemManager1.Modem.xml
+++ b/introspection/org.freedesktop.ModemManager1.Modem.xml
@@ -200,17 +200,17 @@
<property name="Sim" type="o" access="read" />
<!--
- ModemCapabilities:
+ SupportedCapabilities:
- Bitmask of <link linkend="MMModemCapability">MMModemCapability</link>
- values, specifying the generic family of access technologies the modem
- supports.
+ List of <link linkend="MMModemCapability">MMModemCapability</link>
+ values, specifying the combinations of generic family of access
+ technologies the modem supports.
- Not all capabilities are available at the same time however; some
- modems require a firmware reload or other reinitialization to switch
- between e.g. CDMA/EVDO and GSM/UMTS.
+ If the modem doesn't allow changing the current capabilities, a single entry with
+ <link linkend="MM-MODEM-CAPABILITY-ANY:CAPS"><constant>MM_MODEM_CAPABILITY_ANY</constant></link>
+ will be given.
-->
- <property name="ModemCapabilities" type="u" access="read" />
+ <property name="SupportedCapabilities" type="au" access="read" />
<!--
CurrentCapabilities:
diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c
index 2b158354..04ffe36d 100644
--- a/libmm-glib/mm-common-helpers.c
+++ b/libmm-glib/mm-common-helpers.c
@@ -26,6 +26,34 @@
#include "mm-common-helpers.h"
gchar *
+mm_common_build_capabilities_string (const MMModemCapability *capabilities,
+ guint n_capabilities)
+{
+ gboolean first = TRUE;
+ GString *str;
+ guint i;
+
+ if (!capabilities || !n_capabilities)
+ return g_strdup ("none");
+
+ str = g_string_new ("");
+ for (i = 0; i < n_capabilities; i++) {
+ gchar *tmp;
+
+ tmp = mm_modem_capability_build_string_from_mask (capabilities[i]);
+ g_string_append_printf (str, "%s%s",
+ first ? "" : "\n",
+ tmp);
+ g_free (tmp);
+
+ if (first)
+ first = FALSE;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+gchar *
mm_common_build_bands_string (const MMModemBand *bands,
guint n_bands)
{
@@ -216,6 +244,103 @@ mm_common_get_modes_from_string (const gchar *str,
return modes;
}
+GArray *
+mm_common_capability_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) {
+ guint32 capability;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), n);
+ while (g_variant_iter_loop (&iter, "u", &capability))
+ g_array_append_val (array, capability);
+ }
+ }
+
+ /* If nothing set, fallback to default */
+ if (!array) {
+ guint32 capability = MM_MODEM_CAPABILITY_NONE;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 1);
+ g_array_append_val (array, capability);
+ }
+
+ return array;
+}
+
+MMModemCapability *
+mm_common_capability_combinations_variant_to_array (GVariant *variant,
+ guint *n_capabilities)
+{
+ GArray *array;
+
+ array = mm_common_capability_combinations_variant_to_garray (variant);
+ if (n_capabilities)
+ *n_capabilities = array->len;
+ return (MMModemCapability *) g_array_free (array, FALSE);
+}
+
+GVariant *
+mm_common_capability_combinations_array_to_variant (const MMModemCapability *capabilities,
+ guint n_capabilities)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+
+ if (n_capabilities > 0) {
+ guint i;
+
+ for (i = 0; i < n_capabilities; i++)
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 ((guint32)capabilities[i]));
+ } else
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 (MM_MODEM_CAPABILITY_NONE));
+
+ return g_variant_builder_end (&builder);
+}
+
+GVariant *
+mm_common_capability_combinations_garray_to_variant (GArray *array)
+{
+ if (array)
+ return mm_common_capability_combinations_array_to_variant ((const MMModemCapability *)array->data,
+ array->len);
+
+ return mm_common_capability_combinations_array_to_variant (NULL, 0);
+}
+
+GVariant *
+mm_common_build_capability_combinations_none (void)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 (MM_MODEM_CAPABILITY_NONE));
+ return g_variant_builder_end (&builder);
+}
+
+GVariant *
+mm_common_build_capability_combinations_any (void)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 (MM_MODEM_CAPABILITY_ANY));
+ return g_variant_builder_end (&builder);
+}
+
void
mm_common_get_bands_from_string (const gchar *str,
MMModemBand **bands,
diff --git a/libmm-glib/mm-common-helpers.h b/libmm-glib/mm-common-helpers.h
index 45df4f4c..891eb9da 100644
--- a/libmm-glib/mm-common-helpers.h
+++ b/libmm-glib/mm-common-helpers.h
@@ -26,6 +26,9 @@
#ifndef MM_COMMON_HELPERS_H
#define MM_COMMON_HELPERS_H
+gchar *mm_common_build_capabilities_string (const MMModemCapability *capabilities,
+ guint n_capabilities);
+
gchar *mm_common_build_bands_string (const MMModemBand *bands,
guint n_bands);
@@ -79,6 +82,15 @@ GVariant *mm_common_mode_combinations_array_to_variant (const MMM
GVariant *mm_common_mode_combinations_garray_to_variant (GArray *array);
GVariant *mm_common_build_mode_combinations_default (void);
+GArray *mm_common_capability_combinations_variant_to_garray (GVariant *variant);
+MMModemCapability *mm_common_capability_combinations_variant_to_array (GVariant *variant,
+ guint *n_capabilities);
+GVariant *mm_common_capability_combinations_array_to_variant (const MMModemCapability *capabilities,
+ guint n_capabilities);
+GVariant *mm_common_capability_combinations_garray_to_variant (GArray *array);
+GVariant *mm_common_build_capability_combinations_any (void);
+GVariant *mm_common_build_capability_combinations_none (void);
+
typedef gboolean (*MMParseKeyValueForeachFn) (const gchar *key,
const gchar *value,
gpointer user_data);
diff --git a/libmm-glib/mm-modem.c b/libmm-glib/mm-modem.c
index 715bca52..39c7ff2e 100644
--- a/libmm-glib/mm-modem.c
+++ b/libmm-glib/mm-modem.c
@@ -54,6 +54,11 @@ struct _MMModemPrivate {
guint supported_modes_id;
GArray *supported_modes;
+ /* Supported Capabilities */
+ GMutex supported_capabilities_mutex;
+ guint supported_capabilities_id;
+ GArray *supported_capabilities;
+
/* Supported Bands */
GMutex supported_bands_mutex;
guint supported_bands_id;
@@ -148,24 +153,118 @@ mm_modem_dup_sim_path (MMModem *self)
/*****************************************************************************/
+static void
+supported_capabilities_updated (MMModem *self,
+ GParamSpec *pspec)
+{
+ g_mutex_lock (&self->priv->supported_capabilities_mutex);
+ {
+ GVariant *dictionary;
+
+ if (self->priv->supported_capabilities)
+ g_array_unref (self->priv->supported_capabilities);
+
+ dictionary = mm_gdbus_modem_get_supported_capabilities (MM_GDBUS_MODEM (self));
+ self->priv->supported_capabilities = (dictionary ?
+ mm_common_capability_combinations_variant_to_garray (dictionary) :
+ NULL);
+ }
+ g_mutex_unlock (&self->priv->supported_capabilities_mutex);
+}
+
+static gboolean
+ensure_internal_supported_capabilities (MMModem *self,
+ MMModemCapability **dup_capabilities,
+ guint *dup_capabilities_n)
+{
+ gboolean ret;
+
+ g_mutex_lock (&self->priv->supported_capabilities_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_capabilities_id) {
+ GVariant *dictionary;
+
+ dictionary = mm_gdbus_modem_dup_supported_capabilities (MM_GDBUS_MODEM (self));
+ if (dictionary) {
+ self->priv->supported_capabilities = mm_common_capability_combinations_variant_to_garray (dictionary);
+ g_variant_unref (dictionary);
+ }
+
+ /* No need to clear this signal connection when freeing self */
+ self->priv->supported_capabilities_id =
+ g_signal_connect (self,
+ "notify::supported-capabilities",
+ G_CALLBACK (supported_capabilities_updated),
+ NULL);
+ }
+
+ if (!self->priv->supported_capabilities)
+ ret = FALSE;
+ else {
+ ret = TRUE;
+
+ if (dup_capabilities && dup_capabilities_n) {
+ *dup_capabilities_n = self->priv->supported_capabilities->len;
+ if (self->priv->supported_capabilities->len > 0) {
+ *dup_capabilities = g_malloc (sizeof (MMModemCapability) * self->priv->supported_capabilities->len);
+ memcpy (*dup_capabilities, self->priv->supported_capabilities->data, sizeof (MMModemCapability) * self->priv->supported_capabilities->len);
+ } else
+ *dup_capabilities = NULL;
+ }
+ }
+ }
+ g_mutex_unlock (&self->priv->supported_capabilities_mutex);
+
+ return ret;
+}
+
/**
- * mm_modem_get_modem_capabilities:
+ * mm_modem_get_supported_capabilities:
* @self: A #MMModem.
+ * @capabilities: (out) (array length=n_capabilities): Return location for the array of #MMModemCapability values. The returned array should be freed with g_free() when no longer needed.
+ * @n_capabilities: (out): Return location for the number of values in @capabilities.
*
- * Gets the list of generic families of access technologies supported by this #MMModem.
+ * Gets the list of combinations of generic families of access technologies supported by this #MMModem.
*
- * Not all capabilities are available at the same time however; some
- * modems require a firmware reload or other reinitialization to switch
- * between e.g. CDMA/EVDO and GSM/UMTS.
+ * Returns: %TRUE if @capabilities and @n_capabilities are set, %FALSE otherwise.
+ */
+gboolean
+mm_modem_get_supported_capabilities (MMModem *self,
+ MMModemCapability **capabilities,
+ guint *n_capabilities)
+{
+ g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
+
+ return ensure_internal_supported_capabilities (self, capabilities, n_capabilities);
+}
+
+/**
+ * mm_modem_peek_supported_capabilities:
+ * @self: A #MMModem.
+ * @capabilities: (out) (array length=n_capabilities): Return location for the array of #MMModemCapability values. Do not free the returned array, it is owned by @self.
+ * @n_capabilities: (out): Return location for the number of values in @capabilities.
*
- * Returns: A bitmask of #MMModemCapability flags.
+ * Gets the list of combinations of generic families of access technologies supported by this #MMModem.
+ *
+ * Returns: %TRUE if @capabilities and @n_capabilities are set, %FALSE otherwise.
*/
-MMModemCapability
-mm_modem_get_modem_capabilities (MMModem *self)
+gboolean
+mm_modem_peek_supported_capabilities (MMModem *self,
+ const MMModemCapability **capabilities,
+ guint *n_capabilities)
{
- g_return_val_if_fail (MM_IS_MODEM (self), MM_MODEM_CAPABILITY_NONE);
+ g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
+ g_return_val_if_fail (capabilities != NULL, FALSE);
+ g_return_val_if_fail (n_capabilities != NULL, FALSE);
- return (MMModemCapability) mm_gdbus_modem_get_modem_capabilities (MM_GDBUS_MODEM (self));
+ if (!ensure_internal_supported_capabilities (self, NULL, NULL))
+ return FALSE;
+
+ *n_capabilities = self->priv->supported_capabilities->len;
+ *capabilities = (MMModemCapability *)self->priv->supported_capabilities->data;
+ return TRUE;
}
/*****************************************************************************/
@@ -2642,6 +2741,7 @@ mm_modem_init (MMModem *self)
MMModemPrivate);
g_mutex_init (&self->priv->unlock_retries_mutex);
g_mutex_init (&self->priv->supported_modes_mutex);
+ g_mutex_init (&self->priv->supported_capabilities_mutex);
g_mutex_init (&self->priv->supported_bands_mutex);
g_mutex_init (&self->priv->current_bands_mutex);
}
@@ -2658,6 +2758,8 @@ finalize (GObject *object)
if (self->priv->supported_modes)
g_array_unref (self->priv->supported_modes);
+ if (self->priv->supported_capabilities)
+ g_array_unref (self->priv->supported_capabilities);
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 434f3885..3990a59d 100644
--- a/libmm-glib/mm-modem.h
+++ b/libmm-glib/mm-modem.h
@@ -74,7 +74,12 @@ gchar *mm_modem_dup_path (MMModem *self);
const gchar *mm_modem_get_sim_path (MMModem *self);
gchar *mm_modem_dup_sim_path (MMModem *self);
-MMModemCapability mm_modem_get_modem_capabilities (MMModem *self);
+gboolean mm_modem_peek_supported_capabilities (MMModem *self,
+ const MMModemCapability **capabilities,
+ guint *n_capabilities);
+gboolean mm_modem_get_supported_capabilities (MMModem *self,
+ MMModemCapability **capabilities,
+ guint *n_capabilities);
MMModemCapability mm_modem_get_current_capabilities (MMModem *self);
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c
index 5c9f3478..15b93d93 100644
--- a/src/mm-broadband-modem-mbim.c
+++ b/src/mm-broadband-modem-mbim.c
@@ -2169,8 +2169,6 @@ iface_modem_init (MMIfaceModem *iface)
/* Initialization steps */
iface->load_current_capabilities = modem_load_current_capabilities;
iface->load_current_capabilities_finish = modem_load_current_capabilities_finish;
- iface->load_modem_capabilities = NULL;
- iface->load_modem_capabilities_finish = NULL;
iface->load_manufacturer = modem_load_manufacturer;
iface->load_manufacturer_finish = modem_load_manufacturer_finish;
iface->load_model = modem_load_model;
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 3e4ced73..8091c036 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -555,46 +555,37 @@ modem_load_current_capabilities (MMIfaceModem *self,
}
/*****************************************************************************/
-/* Modem Capabilities loading (Modem interface) */
+/* Supported capabilities loading (Modem interface) */
typedef struct {
MMBroadbandModemQmi *self;
GSimpleAsyncResult *result;
-} LoadModemCapabilitiesContext;
+} LoadSupportedCapabilitiesContext;
static void
-load_modem_capabilities_context_complete_and_free (LoadModemCapabilitiesContext *ctx)
+load_supported_capabilities_context_complete_and_free (LoadSupportedCapabilitiesContext *ctx)
{
g_simple_async_result_complete (ctx->result);
g_object_unref (ctx->result);
g_object_unref (ctx->self);
- g_slice_free (LoadModemCapabilitiesContext, ctx);
+ g_slice_free (LoadSupportedCapabilitiesContext, ctx);
}
-static MMModemCapability
-modem_load_modem_capabilities_finish (MMIfaceModem *self,
- GAsyncResult *res,
- GError **error)
+static GArray *
+modem_load_supported_capabilities_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
{
- MMModemCapability caps;
- gchar *caps_str;
-
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
- return MM_MODEM_CAPABILITY_NONE;
+ return NULL;
- caps = ((MMModemCapability) GPOINTER_TO_UINT (
- g_simple_async_result_get_op_res_gpointer (
- G_SIMPLE_ASYNC_RESULT (res))));
- caps_str = mm_modem_capability_build_string_from_mask (caps);
- mm_dbg ("loaded modem capabilities: %s", caps_str);
- g_free (caps_str);
- return caps;
+ return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
}
static void
dms_get_capabilities_ready (QmiClientDms *client,
GAsyncResult *res,
- LoadModemCapabilitiesContext *ctx)
+ LoadSupportedCapabilitiesContext *ctx)
{
QmiMessageDmsGetCapabilitiesOutput *output = NULL;
GError *error = NULL;
@@ -604,12 +595,15 @@ dms_get_capabilities_ready (QmiClientDms *client,
g_prefix_error (&error, "QMI operation failed: ");
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_prefix_error (&error, "Couldn't get supported capabilities: ");
g_simple_async_result_take_error (ctx->result, error);
} else {
guint i;
- guint mask = MM_MODEM_CAPABILITY_NONE;
+ MMModemCapability mask = MM_MODEM_CAPABILITY_NONE;
+ MMModemCapability single;
GArray *radio_interface_list;
+ GArray *supported_combinations;
+ GArray *filtered_combinations;
qmi_message_dms_get_capabilities_output_get_info (
output,
@@ -631,23 +625,55 @@ dms_get_capabilities_ready (QmiClientDms *client,
g_array_unref (ctx->self->priv->supported_radio_interfaces);
ctx->self->priv->supported_radio_interfaces = g_array_ref (radio_interface_list);
+ supported_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 7);
+
+ /* Add all possible supported capability combinations, we will filter
+ * them out afterwards */
+
+ /* GSM/UMTS */
+ single = MM_MODEM_CAPABILITY_GSM_UMTS;
+ g_array_append_val (supported_combinations, single);
+ /* CDMA/EVDO */
+ single = MM_MODEM_CAPABILITY_CDMA_EVDO;
+ g_array_append_val (supported_combinations, single);
+ /* LTE only */
+ single = MM_MODEM_CAPABILITY_LTE;
+ g_array_append_val (supported_combinations, single);
+ /* GSM/UMTS + CDMA/EVDO */
+ single = (MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_GSM_UMTS);
+ g_array_append_val (supported_combinations, single);
+ /* GSM/UMTS + LTE */
+ single = (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE);
+ g_array_append_val (supported_combinations, single);
+ /* CDMA/EVDO + LTE */
+ single = (MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_LTE);
+ g_array_append_val (supported_combinations, single);
+ /* GSM/UMTS + CDMA/EVDO + LTE */
+ single = (MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE);
+ g_array_append_val (supported_combinations, single);
+
+ /* Now filter out based on the real capabilities of the modem */
+ filtered_combinations = mm_filter_supported_capabilities (mask,
+ supported_combinations);
+ g_array_unref (supported_combinations);
+
g_simple_async_result_set_op_res_gpointer (ctx->result,
- GUINT_TO_POINTER (mask),
- NULL);
+ filtered_combinations,
+ (GDestroyNotify) g_array_unref);
}
if (output)
qmi_message_dms_get_capabilities_output_unref (output);
- load_modem_capabilities_context_complete_and_free (ctx);
+ load_supported_capabilities_context_complete_and_free (ctx);
}
static void
-modem_load_modem_capabilities (MMIfaceModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+modem_load_supported_capabilities (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- LoadModemCapabilitiesContext *ctx;
+ LoadSupportedCapabilitiesContext *ctx;
QmiClient *client = NULL;
if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
@@ -655,14 +681,14 @@ modem_load_modem_capabilities (MMIfaceModem *self,
callback, user_data))
return;
- ctx = g_slice_new (LoadModemCapabilitiesContext);
+ ctx = g_slice_new (LoadSupportedCapabilitiesContext);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
- modem_load_modem_capabilities);
+ modem_load_supported_capabilities);
- mm_dbg ("loading modem capabilities...");
+ mm_dbg ("loading supported capabilities...");
qmi_client_dms_get_capabilities (QMI_CLIENT_DMS (client),
NULL,
5,
@@ -8182,8 +8208,8 @@ iface_modem_init (MMIfaceModem *iface)
/* Initialization steps */
iface->load_current_capabilities = modem_load_current_capabilities;
iface->load_current_capabilities_finish = modem_load_current_capabilities_finish;
- iface->load_modem_capabilities = modem_load_modem_capabilities;
- iface->load_modem_capabilities_finish = modem_load_modem_capabilities_finish;
+ iface->load_supported_capabilities = modem_load_supported_capabilities;
+ iface->load_supported_capabilities_finish = modem_load_supported_capabilities_finish;
iface->load_manufacturer = modem_load_manufacturer;
iface->load_manufacturer_finish = modem_load_manufacturer_finish;
iface->load_model = modem_load_model;
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index 59be9e67..9f9ad50d 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -3501,7 +3501,7 @@ static void interface_initialization_step (InitializationContext *ctx);
typedef enum {
INITIALIZATION_STEP_FIRST,
INITIALIZATION_STEP_CURRENT_CAPABILITIES,
- INITIALIZATION_STEP_MODEM_CAPABILITIES,
+ INITIALIZATION_STEP_SUPPORTED_CAPABILITIES,
INITIALIZATION_STEP_BEARERS,
INITIALIZATION_STEP_MANUFACTURER,
INITIALIZATION_STEP_MODEL,
@@ -3681,7 +3681,33 @@ load_current_capabilities_ready (MMIfaceModem *self,
interface_initialization_step (ctx);
}
-UINT_REPLY_READY_FN (modem_capabilities, "Modem Capabilities")
+static void
+load_supported_capabilities_ready (MMIfaceModem *self,
+ GAsyncResult *res,
+ InitializationContext *ctx)
+{
+ GArray *supported_capabilities;
+ GError *error = NULL;
+
+ supported_capabilities = MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_capabilities_finish (self, res, &error);
+ if (error) {
+ g_propagate_error (&ctx->fatal_error, error);
+ g_prefix_error (&ctx->fatal_error, "couldn't load supported capabilities: ");
+ /* Jump to the last step */
+ ctx->step = INITIALIZATION_STEP_LAST;
+ interface_initialization_step (ctx);
+ return;
+ }
+
+ /* Update supported caps */
+ mm_gdbus_modem_set_supported_capabilities (ctx->skeleton,
+ mm_common_capability_combinations_garray_to_variant (supported_capabilities));
+ g_array_unref (supported_capabilities);
+
+ ctx->step++;
+ interface_initialization_step (ctx);
+}
+
STR_REPLY_READY_FN (manufacturer, "Manufacturer")
STR_REPLY_READY_FN (model, "Model")
STR_REPLY_READY_FN (revision, "Revision")
@@ -3935,26 +3961,42 @@ interface_initialization_step (InitializationContext *ctx)
/* Fall down to next step */
ctx->step++;
- case INITIALIZATION_STEP_MODEM_CAPABILITIES:
- /* Modem capabilities are meant to be loaded only once during the whole
+ case INITIALIZATION_STEP_SUPPORTED_CAPABILITIES: {
+ GArray *supported_capabilities;
+
+ supported_capabilities = (mm_common_capability_combinations_variant_to_garray (
+ mm_gdbus_modem_get_supported_capabilities (ctx->skeleton)));
+
+ /* Supported capabilities 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_modem_capabilities (ctx->skeleton) == MM_MODEM_CAPABILITY_NONE &&
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_modem_capabilities &&
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_modem_capabilities_finish) {
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_modem_capabilities (
- ctx->self,
- (GAsyncReadyCallback)load_modem_capabilities_ready,
- ctx);
- return;
+ if (supported_capabilities->len == 0 ||
+ g_array_index (supported_capabilities, MMModemCapability, 0) == MM_MODEM_CAPABILITY_NONE) {
+ MMModemCapability current;
+
+ if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_capabilities &&
+ MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_capabilities_finish) {
+ MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_supported_capabilities (
+ ctx->self,
+ (GAsyncReadyCallback)load_supported_capabilities_ready,
+ ctx);
+ return;
+ }
+
+ /* If no specific way of getting modem capabilities, default to the current ones */
+ g_array_unref (supported_capabilities);
+ supported_capabilities = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 1);
+ current = mm_gdbus_modem_get_current_capabilities (ctx->skeleton);
+ g_array_append_val (supported_capabilities, current);
+ mm_gdbus_modem_set_supported_capabilities (
+ ctx->skeleton,
+ mm_common_capability_combinations_garray_to_variant (supported_capabilities));
}
- /* If no specific way of getting modem capabilities, assume they are
- * equal to the current capabilities */
- mm_gdbus_modem_set_modem_capabilities (
- ctx->skeleton,
- mm_gdbus_modem_get_current_capabilities (ctx->skeleton));
+ g_array_unref (supported_capabilities);
+
/* Fall down to next step */
ctx->step++;
+ }
case INITIALIZATION_STEP_BEARERS: {
MMBearerList *list = NULL;
@@ -4318,8 +4360,8 @@ mm_iface_modem_initialize (MMIfaceModem *self,
/* Set all initial property defaults */
mm_gdbus_modem_set_sim (skeleton, NULL);
+ mm_gdbus_modem_set_supported_capabilities (skeleton, mm_common_build_capability_combinations_none ());
mm_gdbus_modem_set_current_capabilities (skeleton, MM_MODEM_CAPABILITY_NONE);
- mm_gdbus_modem_set_modem_capabilities (skeleton, MM_MODEM_CAPABILITY_NONE);
mm_gdbus_modem_set_max_bearers (skeleton, 0);
mm_gdbus_modem_set_max_active_bearers (skeleton, 0);
mm_gdbus_modem_set_manufacturer (skeleton, NULL);
diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
index 8ba1da66..8f87bc6b 100644
--- a/src/mm-iface-modem.h
+++ b/src/mm-iface-modem.h
@@ -42,13 +42,13 @@ typedef struct _MMIfaceModem MMIfaceModem;
struct _MMIfaceModem {
GTypeInterface g_iface;
- /* Loading of the ModemCapabilities property */
- void (*load_modem_capabilities) (MMIfaceModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data);
- MMModemCapability (*load_modem_capabilities_finish) (MMIfaceModem *self,
- GAsyncResult *res,
- GError **error);
+ /* Loading of the SupportedCapabilities property */
+ void (*load_supported_capabilities) (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ GArray * (*load_supported_capabilities_finish) (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error);
/* Loading of the CurrentCapabilities property */
void (*load_current_capabilities) (MMIfaceModem *self,
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 6d0acb20..cd4ef763 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -295,6 +295,34 @@ mm_filter_supported_modes (const GArray *all,
/*****************************************************************************/
+GArray *
+mm_filter_supported_capabilities (MMModemCapability all,
+ const GArray *supported_combinations)
+{
+ guint i;
+ GArray *filtered_combinations;
+
+ g_return_val_if_fail (all != MM_MODEM_CAPABILITY_NONE, NULL);
+ g_return_val_if_fail (supported_combinations != NULL, NULL);
+
+ /* We will filter out all combinations which have modes not listed in 'all' */
+ filtered_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), supported_combinations->len);
+ for (i = 0; i < supported_combinations->len; i++) {
+ MMModemCapability capability;
+
+ capability = g_array_index (supported_combinations, MMModemCapability, i);
+ if (!(capability & ~all))
+ g_array_append_val (filtered_combinations, capability);
+ }
+
+ if (filtered_combinations->len == 0)
+ mm_warn ("All supported capability combinations were filtered out.");
+
+ 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 ce7c66d1..a1f12329 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -76,6 +76,9 @@ gchar *mm_new_iso8601_time (guint year,
GArray *mm_filter_supported_modes (const GArray *all,
const GArray *supported_combinations);
+GArray *mm_filter_supported_capabilities (MMModemCapability 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 c61f190c..f988dfaa 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -2053,6 +2053,98 @@ test_supported_mode_filter (void *f, gpointer d)
/*****************************************************************************/
+static gboolean
+find_capability_combination (GArray *capabilities,
+ MMModemCapability capability)
+{
+ guint i;
+
+ for (i = 0; i < capabilities->len; i++) {
+ MMModemCapability capability_i;
+
+ capability_i = g_array_index (capabilities, MMModemCapability, i);
+ if (capability_i == capability)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+test_supported_capability_filter (void *f, gpointer d)
+{
+ MMModemCapability capability;
+ GArray *combinations;
+ GArray *filtered;
+
+ combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 6);
+
+ /* GSM/UMTS only */
+ capability = MM_MODEM_CAPABILITY_GSM_UMTS;
+ g_array_append_val (combinations, capability);
+ /* CDMA/EVDO only */
+ capability = MM_MODEM_CAPABILITY_CDMA_EVDO;
+ g_array_append_val (combinations, capability);
+ /* GSM/UMTS and CDMA/EVDO */
+ capability = (MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_GSM_UMTS);
+ g_array_append_val (combinations, capability);
+ /* GSM/UMTS+LTE */
+ capability = (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE);
+ g_array_append_val (combinations, capability);
+ /* CDMA/EVDO+LTE */
+ capability = (MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_LTE);
+ g_array_append_val (combinations, capability);
+ /* GSM/UMTS+CDMA/EVDO+LTE */
+ capability = (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_LTE);
+ g_array_append_val (combinations, capability);
+
+ /* Only GSM-UMTS supported */
+ filtered = mm_filter_supported_capabilities (MM_MODEM_CAPABILITY_GSM_UMTS, combinations);
+ g_assert_cmpuint (filtered->len, ==, 1);
+ g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_GSM_UMTS));
+ g_array_unref (filtered);
+
+ /* Only CDMA-EVDO supported */
+ filtered = mm_filter_supported_capabilities (MM_MODEM_CAPABILITY_CDMA_EVDO, combinations);
+ g_assert_cmpuint (filtered->len, ==, 1);
+ g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_CDMA_EVDO));
+ g_array_unref (filtered);
+
+ /* GSM-UMTS and CDMA-EVDO supported */
+ filtered = mm_filter_supported_capabilities ((MM_MODEM_CAPABILITY_CDMA_EVDO |
+ MM_MODEM_CAPABILITY_GSM_UMTS),
+ combinations);
+ g_assert_cmpuint (filtered->len, ==, 3);
+ g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_CDMA_EVDO));
+ g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_GSM_UMTS));
+ g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS |
+ MM_MODEM_CAPABILITY_CDMA_EVDO)));
+ g_array_unref (filtered);
+
+ /* GSM-UMTS, CDMA-EVDO and LTE supported */
+ filtered = mm_filter_supported_capabilities ((MM_MODEM_CAPABILITY_CDMA_EVDO |
+ MM_MODEM_CAPABILITY_GSM_UMTS |
+ MM_MODEM_CAPABILITY_LTE),
+ combinations);
+ g_assert_cmpuint (filtered->len, ==, 6);
+ g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_CDMA_EVDO));
+ g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_GSM_UMTS));
+ g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS |
+ MM_MODEM_CAPABILITY_CDMA_EVDO)));
+ g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS |
+ MM_MODEM_CAPABILITY_LTE)));
+ g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_CDMA_EVDO |
+ MM_MODEM_CAPABILITY_LTE)));
+ g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS |
+ MM_MODEM_CAPABILITY_CDMA_EVDO |
+ MM_MODEM_CAPABILITY_LTE)));
+ g_array_unref (filtered);
+
+ g_array_unref (combinations);
+}
+
+/*****************************************************************************/
+
void
_mm_log (const char *loc,
const char *func,
@@ -2184,6 +2276,8 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_supported_mode_filter, NULL));
+ g_test_suite_add (suite, TESTCASE (test_supported_capability_filter, NULL));
+
result = g_test_run ();
reg_test_data_free (reg_data);