diff options
-rw-r--r-- | cli/mmcli-modem.c | 24 | ||||
-rw-r--r-- | docs/reference/libmm-glib/libmm-glib-sections.txt | 8 | ||||
-rw-r--r-- | include/ModemManager-enums.h | 2 | ||||
-rw-r--r-- | introspection/org.freedesktop.ModemManager1.Modem.xml | 16 | ||||
-rw-r--r-- | libmm-glib/mm-common-helpers.c | 125 | ||||
-rw-r--r-- | libmm-glib/mm-common-helpers.h | 12 | ||||
-rw-r--r-- | libmm-glib/mm-modem.c | 122 | ||||
-rw-r--r-- | libmm-glib/mm-modem.h | 7 | ||||
-rw-r--r-- | src/mm-broadband-modem-mbim.c | 2 | ||||
-rw-r--r-- | src/mm-broadband-modem-qmi.c | 94 | ||||
-rw-r--r-- | src/mm-iface-modem.c | 78 | ||||
-rw-r--r-- | src/mm-iface-modem.h | 14 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 28 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 3 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 94 |
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); |