diff options
-rw-r--r-- | cli/mmcli-modem.c | 2 | ||||
-rw-r--r-- | cli/mmcli-output.c | 35 | ||||
-rw-r--r-- | cli/mmcli-output.h | 20 | ||||
-rw-r--r-- | docs/reference/libmm-glib/libmm-glib-sections.txt | 11 | ||||
-rw-r--r-- | introspection/org.freedesktop.ModemManager1.Modem.xml | 47 | ||||
-rw-r--r-- | libmm-glib/mm-modem.c | 316 | ||||
-rw-r--r-- | libmm-glib/mm-modem.h | 16 | ||||
-rw-r--r-- | src/mm-broadband-modem.c | 14 | ||||
-rw-r--r-- | src/mm-iface-modem.c | 94 | ||||
-rw-r--r-- | src/mm-iface-modem.h | 11 | ||||
-rw-r--r-- | src/mm-private-boxed-types.c | 29 | ||||
-rw-r--r-- | src/mm-private-boxed-types.h | 3 |
12 files changed, 587 insertions, 11 deletions
diff --git a/cli/mmcli-modem.c b/cli/mmcli-modem.c index a25de316..2ca24495 100644 --- a/cli/mmcli-modem.c +++ b/cli/mmcli-modem.c @@ -475,6 +475,8 @@ print_modem_info (void) sim_path = mm_modem_get_sim_path (ctx->modem); mmcli_output_string (MMC_F_SIM_PATH, g_strcmp0 (sim_path, "/") != 0 ? sim_path : NULL); + mmcli_output_sim_slots (mm_modem_dup_sim_slot_paths (ctx->modem), + mm_modem_get_primary_sim_slot (ctx->modem)); bearer_paths = (const gchar **) mm_modem_get_bearer_paths (ctx->modem); mmcli_output_string_array (MMC_F_BEARER_PATHS, (bearer_paths && bearer_paths[0]) ? bearer_paths : NULL, TRUE); diff --git a/cli/mmcli-output.c b/cli/mmcli-output.c index 7f68e812..ec540545 100644 --- a/cli/mmcli-output.c +++ b/cli/mmcli-output.c @@ -147,7 +147,9 @@ static FieldInfo field_infos[] = { [MMC_F_CDMA_REGISTRATION_CDMA1X] = { "modem.cdma.cdma1x-registration-state", "registration cdma1x", MMC_S_MODEM_CDMA, }, [MMC_F_CDMA_REGISTRATION_EVDO] = { "modem.cdma.evdo-registration-state", "registration evdo", MMC_S_MODEM_CDMA, }, [MMC_F_CDMA_ACTIVATION] = { "modem.cdma.activation-state", "activation", MMC_S_MODEM_CDMA, }, - [MMC_F_SIM_PATH] = { "modem.generic.sim", "path", MMC_S_MODEM_SIM, }, + [MMC_F_SIM_PATH] = { "modem.generic.sim", "primary sim path", MMC_S_MODEM_SIM, }, + [MMC_F_SIM_PRIMARY_SLOT] = { "modem.generic.primary-sim-slot", NULL, MMC_S_MODEM_SIM, }, + [MMC_F_SIM_SLOT_PATHS] = { "modem.generic.sim-slots", "sim slot paths", MMC_S_MODEM_SIM, }, [MMC_F_BEARER_PATHS] = { "modem.generic.bearers", "paths", MMC_S_MODEM_BEARER, }, [MMC_F_TIME_CURRENT] = { "modem.time.current", "current", MMC_S_MODEM_TIME, }, [MMC_F_TIMEZONE_CURRENT] = { "modem.timezone.current", "current", MMC_S_MODEM_TIMEZONE, }, @@ -570,6 +572,37 @@ mmcli_output_state (MMModemState state, } /******************************************************************************/ +/* (Custom) SIM slots output */ + +void +mmcli_output_sim_slots (gchar **sim_slot_paths, + guint primary_sim_slot) +{ + guint i; + + if (selected_type != MMC_OUTPUT_TYPE_HUMAN || !sim_slot_paths) { + mmcli_output_string_take (MMC_F_SIM_PRIMARY_SLOT, primary_sim_slot ? g_strdup_printf ("%u", primary_sim_slot) : NULL); + mmcli_output_string_array_take (MMC_F_SIM_SLOT_PATHS, sim_slot_paths ? sim_slot_paths : NULL, TRUE); + return; + } + + /* Include SIM slot number in each item */ + for (i = 0; sim_slot_paths[i]; i++) { + gchar *aux; + guint slot_number = i + 1; + + aux = g_strdup_printf ("slot %u: %s%s", + slot_number, + g_str_equal (sim_slot_paths[i], "/") ? "none" : sim_slot_paths[i], + (primary_sim_slot == slot_number) ? " (active)" : ""); + g_free (sim_slot_paths[i]); + sim_slot_paths[i] = aux; + } + + mmcli_output_string_array_take (MMC_F_SIM_SLOT_PATHS, sim_slot_paths, TRUE); +} + +/******************************************************************************/ /* (Custom) Network scan output */ static gchar * diff --git a/cli/mmcli-output.h b/cli/mmcli-output.h index 0bf40a41..98702d3a 100644 --- a/cli/mmcli-output.h +++ b/cli/mmcli-output.h @@ -154,6 +154,8 @@ typedef enum { MMC_F_CDMA_ACTIVATION, /* SIM section */ MMC_F_SIM_PATH, + MMC_F_SIM_PRIMARY_SLOT, + MMC_F_SIM_SLOT_PATHS, /* Bearer section */ MMC_F_BEARER_PATHS, /* Time section */ @@ -338,14 +340,16 @@ void mmcli_output_listitem (MmcF field, /******************************************************************************/ /* Custom output management */ -void mmcli_output_signal_quality (guint value, - gboolean recent); -void mmcli_output_state (MMModemState state, - MMModemStateFailedReason reason); -void mmcli_output_scan_networks (GList *network_list); -void mmcli_output_firmware_list (GList *firmware_list, - MMFirmwareProperties *selected); -void mmcli_output_pco_list (GList *pco_list); +void mmcli_output_signal_quality (guint value, + gboolean recent); +void mmcli_output_state (MMModemState state, + MMModemStateFailedReason reason); +void mmcli_output_sim_slots (gchar **sim_slot_paths, + guint primary_sim_slot); +void mmcli_output_scan_networks (GList *network_list); +void mmcli_output_firmware_list (GList *firmware_list, + MMFirmwareProperties *selected); +void mmcli_output_pco_list (GList *pco_list); /******************************************************************************/ /* Dump output */ diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt index 3ffd8c87..eb8d66e2 100644 --- a/docs/reference/libmm-glib/libmm-glib-sections.txt +++ b/docs/reference/libmm-glib/libmm-glib-sections.txt @@ -182,6 +182,12 @@ mm_modem_dup_sim_path mm_modem_get_sim mm_modem_get_sim_finish mm_modem_get_sim_sync +mm_modem_get_sim_slot_paths +mm_modem_dup_sim_slot_paths +mm_modem_get_primary_sim_slot +mm_modem_list_sim_slots +mm_modem_list_sim_slots_finish +mm_modem_list_sim_slots_sync <SUBSECTION Methods> mm_modem_enable mm_modem_enable_finish @@ -2083,6 +2089,9 @@ 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_dup_sim_slots +mm_gdbus_modem_get_sim_slots +mm_gdbus_modem_get_primary_sim_slot mm_gdbus_modem_get_supported_capabilities mm_gdbus_modem_dup_supported_capabilities mm_gdbus_modem_get_state @@ -2153,6 +2162,8 @@ mm_gdbus_modem_set_carrier_configuration_revision mm_gdbus_modem_set_hardware_revision mm_gdbus_modem_set_signal_quality mm_gdbus_modem_set_sim +mm_gdbus_modem_set_sim_slots +mm_gdbus_modem_set_primary_sim_slot mm_gdbus_modem_set_supported_capabilities mm_gdbus_modem_set_state mm_gdbus_modem_set_state_failed_reason diff --git a/introspection/org.freedesktop.ModemManager1.Modem.xml b/introspection/org.freedesktop.ModemManager1.Modem.xml index b026b01f..9b8d2d6d 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.xml @@ -217,11 +217,56 @@ <!-- Sim: - The path of the SIM object available in this device, if any. + The path of the primary active SIM object available in this device, + if any. + + This SIM object is the one used for network registration and data + connection setup. + + If multiple #org.freedesktop.ModemManager1.Modem.SimSlots are + supported, the #org.freedesktop.ModemManager1.Modem.PrimarySimSlot + index value specifies which is the slot number where this SIM card + is available. --> <property name="Sim" type="o" access="read" /> <!-- + SimSlots: + + The list of SIM slots available in the system, including the SIM object + paths if the cards are present. If a given SIM slot at a given index + doesn't have a SIM card available, an empty object path will be given. + + The length of this array of objects will be equal to the amount of + available SIM slots in the system, and the index in the array is the + slot index. + + This list includes the SIM object considered as primary active SIM slot + (#org.freedesktop.ModemManager1.Modem.Sim) at index + #org.freedesktop.ModemManager1.Modem.ActiveSimSlot. + --> + <property name="SimSlots" type="ao" access="read" /> + + <!-- + PrimarySimSlot: + + The index of the primary active SIM slot in the + #org.freedesktop.ModemManager1.Modem.SimSlots array, given in the [1,N] + range. + + If multiple SIM slots aren't supported, this property will report + value 0. + + In a Multi SIM Single Standby setup, this index identifies the only SIM + that is currently active. All the remaining slots will be inactive. + + In a Multi SIM Multi Standby setup, this index identifies the active SIM + that is considered primary, i.e. the one that will be used when a data + connection is setup. + --> + <property name="PrimarySimSlot" type="u" access="read" /> + + <!-- Bearers: The list of bearer object paths (EPS Bearers, PDP Contexts, or diff --git a/libmm-glib/mm-modem.c b/libmm-glib/mm-modem.c index 9a9dbc63..96e113bd 100644 --- a/libmm-glib/mm-modem.c +++ b/libmm-glib/mm-modem.c @@ -172,6 +172,78 @@ mm_modem_dup_sim_path (MMModem *self) /*****************************************************************************/ +/** + * mm_modem_get_sim_slot_paths: + * @self: A #MMModem. + * + * Gets the DBus paths of the #MMSim objects available in the different SIM + * slots handled in this #MMModem. If a given SIM slot at a given index doesn't + * have a SIM card available, an empty object path will be given. This list + * includes the currently active SIM object path. + * + * <warning>The returned value is only valid until the property changes so it is + * only safe to use this function on the thread where @self was constructed. Use + * mm_modem_dup_sim_slot_paths() if on another thread.</warning> + * + * Returns: (transfer none): The DBus paths of the #MMSim objects handled in + * this #MMModem, or %NULL if none available. Do not free the returned value, it + * belongs to @self. + * + * Since: 1.16 + */ +const gchar * const * +mm_modem_get_sim_slot_paths (MMModem *self) +{ + g_return_val_if_fail (MM_IS_MODEM (self), NULL); + + return mm_gdbus_modem_get_sim_slots (MM_GDBUS_MODEM (self)); +} + +/** + * mm_modem_dup_sim_slot_paths: + * @self: A #MMModem. + * + * Gets a copy of the DBus paths of the #MMSim objects available in the + * different SIM slots handled in this #MMModem. If a given SIM slot at a given + * index doesn't have a SIM card available, an empty object path will be given. + * This list includes the currently active SIM object path. + * + * Returns: (transfer full): The DBus paths of the #MMSim objects handled in + * this #MMModem, or %NULL if none available. The returned value should be + * freed with g_strfreev(). + * + * Since: 1.16 + */ +gchar ** +mm_modem_dup_sim_slot_paths (MMModem *self) +{ + g_return_val_if_fail (MM_IS_MODEM (self), NULL); + + return mm_gdbus_modem_dup_sim_slots (MM_GDBUS_MODEM (self)); +} + +/*****************************************************************************/ + +/** + * mm_modem_get_primary_sim_slot: + * @self: A #MMModem. + * + * Gets the SIM slot number of the primary active SIM. + * + * Returns: slot number, in the [1,N] range. + * + * Since: 1.16 + */ +guint +mm_modem_get_primary_sim_slot (MMModem *self) +{ + g_return_val_if_fail (MM_IS_MODEM (self), 0); + + return mm_gdbus_modem_get_primary_sim_slot (MM_GDBUS_MODEM (self)); +} + +/*****************************************************************************/ + static void supported_capabilities_updated (MMModem *self, GParamSpec *pspec) @@ -3383,6 +3455,250 @@ mm_modem_get_sim_sync (MMModem *self, /*****************************************************************************/ +typedef struct { + gchar **sim_paths; + GPtrArray *sim_slots; + guint n_sim_paths; + guint i; +} ListSimSlotsContext; + +static void +list_sim_slots_context_free (ListSimSlotsContext *ctx) +{ + g_strfreev (ctx->sim_paths); + g_ptr_array_unref (ctx->sim_slots); + g_slice_free (ListSimSlotsContext, ctx); +} + +/** + * mm_modem_list_sim_slots_finish: + * @self: A #MMModem. + * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to + * mm_modem_list_sim_slots(). + * @error: Return location for error or %NULL. + * + * Finishes an operation started with mm_modem_list_sim_slots(). + * + * Returns: (transfer full) (element-type ModemManager.Sim): The array of + * #MMSim objects, or %NULL if @error is set. + * + * Since: 1.16 + */ +GPtrArray * +mm_modem_list_sim_slots_finish (MMModem *self, + GAsyncResult *res, + GError **error) +{ + g_return_val_if_fail (MM_IS_MODEM (self), NULL); + + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +sim_slot_free (MMSim *sim) +{ + if (sim) + g_object_unref (sim); +} + +static void create_next_sim (GTask *task); + +static void +modem_list_sim_slots_build_object_ready (GDBusConnection *connection, + GAsyncResult *res, + GTask *task) +{ + GObject *sim; + GError *error = NULL; + GObject *source_object; + ListSimSlotsContext *ctx; + + ctx = g_task_get_task_data (task); + + source_object = g_async_result_get_source_object (res); + sim = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, &error); + g_object_unref (source_object); + + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + g_ptr_array_add (ctx->sim_slots, sim); + + /* Keep on creating next object */ + ctx->i++; + create_next_sim (task); +} + +static void +create_next_sim (GTask *task) +{ + MMModem *self; + ListSimSlotsContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + /* If no more additional sims, just end here. */ + if (ctx->i == ctx->n_sim_paths) { + g_assert_cmpuint (ctx->n_sim_paths, ==, ctx->sim_slots->len); + g_task_return_pointer (task, g_steal_pointer (&ctx->sim_slots), (GDestroyNotify)g_ptr_array_unref); + g_object_unref (task); + return; + } + + /* Empty slot? */ + if (g_str_equal (ctx->sim_paths[ctx->i], "/")) { + g_ptr_array_add (ctx->sim_slots, NULL); + ctx->i++; + create_next_sim (task); + return; + } + + g_async_initable_new_async (MM_TYPE_SIM, + G_PRIORITY_DEFAULT, + g_task_get_cancellable (task), + (GAsyncReadyCallback)modem_list_sim_slots_build_object_ready, + task, + "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "g-name", MM_DBUS_SERVICE, + "g-connection", g_dbus_proxy_get_connection (G_DBUS_PROXY (self)), + "g-object-path", ctx->sim_paths[ctx->i], + "g-interface-name", "org.freedesktop.ModemManager1.Sim", + NULL); +} + +/** + * mm_modem_list_sim_slots: + * @self: A #MMModem. + * @cancellable: (allow-none): A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied or + * %NULL. + * @user_data: User data to pass to @callback. + * + * Asynchronously lists the SIM slots available in the #MMModem. + * + * The returned array contains one element per slot available in the system; + * a #MMSim in each of the slots that contains a valid SIM card or %NULL if + * no SIM card is found. + * + * When the operation is finished, @callback will be invoked in the + * <link linkend="g-main-context-push-thread-default">thread-default main loop</link> + * of the thread you are calling this method from. You can then call + * mm_modem_list_sim_slots_finish() to get the result of the operation. + * + * See mm_modem_list_sim_slots_sync() for the synchronous, blocking version of + * this method. + * + * Since: 1.16 + */ +void +mm_modem_list_sim_slots (MMModem *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + ListSimSlotsContext *ctx; + GTask *task; + + g_return_if_fail (MM_IS_MODEM (self)); + + ctx = g_slice_new0 (ListSimSlotsContext); + ctx->sim_paths = mm_gdbus_modem_dup_sim_slots (MM_GDBUS_MODEM (self)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, ctx, (GDestroyNotify)list_sim_slots_context_free); + + /* If no sim slots, just end here. */ + if (!ctx->sim_paths) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_NOT_FOUND, + "No SIM slots available"); + g_object_unref (task); + return; + } + + /* Got list of paths, start creating objects for each */ + ctx->n_sim_paths = g_strv_length (ctx->sim_paths); + ctx->sim_slots = g_ptr_array_new_full (ctx->n_sim_paths, (GDestroyNotify)sim_slot_free); + ctx->i = 0; + create_next_sim (task); +} + +/** + * mm_modem_list_sim_slots_sync: + * @self: A #MMModem. + * @cancellable: (allow-none): A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Synchronously lists the SIM slots available in the #MMModem. + * + * The returned array contains one element per slot available in the system; + * a #MMSim in each of the slots that contains a valid SIM card or %NULL if + * no SIM card is found. + * + * The calling thread is blocked until a reply is received. See + * mm_modem_list_sim_slots() for the asynchronous version of this method. + * + * Returns: (transfer full) (element-type ModemManager.Sim): The array of + * #MMSim objects, or %NULL if @error is set. + * + * Since: 1.16 + */ +GPtrArray * +mm_modem_list_sim_slots_sync (MMModem *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) sim_slots = NULL; + g_auto(GStrv) sim_paths = NULL; + guint n_sim_paths; + guint i; + + g_return_val_if_fail (MM_IS_MODEM (self), NULL); + + sim_paths = mm_gdbus_modem_dup_sim_slots (MM_GDBUS_MODEM (self)); + + /* Only non-empty lists are returned */ + if (!sim_paths) + return NULL; + + n_sim_paths = g_strv_length (sim_paths); + + sim_slots = g_ptr_array_new_full (n_sim_paths, (GDestroyNotify)sim_slot_free); + for (i = 0; i < n_sim_paths; i++) { + GObject *sim; + + if (g_str_equal (sim_paths[i], "/")) { + g_ptr_array_add (sim_slots, NULL); + continue; + } + + sim = g_initable_new (MM_TYPE_SIM, + cancellable, + error, + "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "g-name", MM_DBUS_SERVICE, + "g-connection", g_dbus_proxy_get_connection (G_DBUS_PROXY (self)), + "g-object-path", sim_paths[i], + "g-interface-name", "org.freedesktop.ModemManager1.Sim", + NULL); + if (!sim) + return NULL; + + /* Keep the object */ + g_ptr_array_add (sim_slots, sim); + } + g_assert_cmpuint (sim_slots->len, ==, n_sim_paths); + + return g_steal_pointer (&sim_slots); +} + +/*****************************************************************************/ + static void mm_modem_init (MMModem *self) { diff --git a/libmm-glib/mm-modem.h b/libmm-glib/mm-modem.h index 0820361d..58732204 100644 --- a/libmm-glib/mm-modem.h +++ b/libmm-glib/mm-modem.h @@ -75,6 +75,11 @@ gchar *mm_modem_dup_path (MMModem *self); const gchar *mm_modem_get_sim_path (MMModem *self); gchar *mm_modem_dup_sim_path (MMModem *self); +const gchar * const *mm_modem_get_sim_slot_paths (MMModem *self); +gchar **mm_modem_dup_sim_slot_paths (MMModem *self); + +guint mm_modem_get_primary_sim_slot (MMModem *self); + gboolean mm_modem_peek_supported_capabilities (MMModem *self, const MMModemCapability **capabilities, guint *n_capabilities); @@ -344,6 +349,17 @@ MMSim *mm_modem_get_sim_sync (MMModem *self, GCancellable *cancellable, GError **error); +void mm_modem_list_sim_slots (MMModem *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GPtrArray *mm_modem_list_sim_slots_finish (MMModem *self, + GAsyncResult *res, + GError **error); +GPtrArray *mm_modem_list_sim_slots_sync (MMModem *self, + GCancellable *cancellable, + GError **error); + G_END_DECLS #endif /* _MM_MODEM_H_ */ diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index aeb660c6..9b10f83e 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -100,6 +100,7 @@ enum { PROP_MODEM_OMA_DBUS_SKELETON, PROP_MODEM_FIRMWARE_DBUS_SKELETON, PROP_MODEM_SIM, + PROP_MODEM_SIM_SLOTS, PROP_MODEM_BEARER_LIST, PROP_MODEM_STATE, PROP_MODEM_3GPP_REGISTRATION_STATE, @@ -153,6 +154,7 @@ struct _MMBroadbandModemPrivate { /* Properties */ GObject *modem_dbus_skeleton; MMBaseSim *modem_sim; + GPtrArray *modem_sim_slots; MMBearerList *modem_bearer_list; MMModemState modem_state; gchar *carrier_config_mapping; @@ -12007,6 +12009,10 @@ set_property (GObject *object, g_clear_object (&self->priv->modem_sim); self->priv->modem_sim = g_value_dup_object (value); break; + case PROP_MODEM_SIM_SLOTS: + g_clear_pointer (&self->priv->modem_sim_slots, g_ptr_array_unref); + self->priv->modem_sim_slots = g_value_dup_boxed (value); + break; case PROP_MODEM_BEARER_LIST: g_clear_object (&self->priv->modem_bearer_list); self->priv->modem_bearer_list = g_value_dup_object (value); @@ -12147,6 +12153,9 @@ get_property (GObject *object, case PROP_MODEM_SIM: g_value_set_object (value, self->priv->modem_sim); break; + case PROP_MODEM_SIM_SLOTS: + g_value_set_boxed (value, self->priv->modem_sim_slots); + break; case PROP_MODEM_BEARER_LIST: g_value_set_object (value, self->priv->modem_bearer_list); break; @@ -12351,6 +12360,7 @@ dispose (GObject *object) g_clear_object (&self->priv->modem_3gpp_initial_eps_bearer); g_clear_object (&self->priv->modem_sim); + g_clear_pointer (&self->priv->modem_sim_slots, g_ptr_array_unref); g_clear_object (&self->priv->modem_bearer_list); g_clear_object (&self->priv->modem_messaging_sms_list); g_clear_object (&self->priv->modem_voice_call_list); @@ -12713,6 +12723,10 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass) MM_IFACE_MODEM_SIM); g_object_class_override_property (object_class, + PROP_MODEM_SIM_SLOTS, + MM_IFACE_MODEM_SIM_SLOTS); + + g_object_class_override_property (object_class, PROP_MODEM_BEARER_LIST, MM_IFACE_MODEM_BEARER_LIST); diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c index 8a4a00af..9045d290 100644 --- a/src/mm-iface-modem.c +++ b/src/mm-iface-modem.c @@ -13,7 +13,6 @@ * Copyright (C) 2011 Google, Inc. */ - #include <ModemManager.h> #define _LIBMM_INSIDE_MM #include <libmm-glib.h> @@ -26,6 +25,7 @@ #include "mm-base-modem-at.h" #include "mm-base-sim.h" #include "mm-bearer-list.h" +#include "mm-private-boxed-types.h" #include "mm-log-object.h" #include "mm-context.h" @@ -4016,6 +4016,7 @@ typedef enum { INITIALIZATION_STEP_SUPPORTED_IP_FAMILIES, INITIALIZATION_STEP_POWER_STATE, INITIALIZATION_STEP_SIM_HOT_SWAP, + INITIALIZATION_STEP_SIM_SLOTS, INITIALIZATION_STEP_UNLOCK_REQUIRED, INITIALIZATION_STEP_SIM, INITIALIZATION_STEP_SETUP_CARRIER_CONFIG, @@ -4401,6 +4402,73 @@ setup_sim_hot_swap_ready (MMIfaceModem *self, } static void +load_sim_slots_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + InitializationContext *ctx; + g_autoptr(GPtrArray) sim_slots = NULL; + g_autoptr(GError) error = NULL; + guint primary_sim_slot = 0; + + ctx = g_task_get_task_data (task); + + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots_finish (self, + res, + &sim_slots, + &primary_sim_slot, + &error)) + mm_obj_warn (self, "couldn't query SIM slots: %s", error->message); + + if (sim_slots) { + MMBaseSim *primary_sim = NULL; + GPtrArray *sim_slot_paths_array; + g_auto(GStrv) sim_slot_paths = NULL; + guint i; + + g_assert (primary_sim_slot); + g_assert_cmpuint (primary_sim_slot, <=, sim_slots->len); + + sim_slot_paths_array = g_ptr_array_new (); + for (i = 0; i < sim_slots->len; i++) { + MMBaseSim *sim; + const gchar *sim_path; + + sim = MM_BASE_SIM (g_ptr_array_index (sim_slots, i)); + if (!sim) { + g_ptr_array_add (sim_slot_paths_array, g_strdup ("/")); + continue; + } + + sim_path = mm_base_sim_get_path (sim); + g_ptr_array_add (sim_slot_paths_array, g_strdup (sim_path)); + } + g_ptr_array_add (sim_slot_paths_array, NULL); + sim_slot_paths = (GStrv) g_ptr_array_free (sim_slot_paths_array, FALSE); + + mm_gdbus_modem_set_sim_slots (ctx->skeleton, (const gchar *const *)sim_slot_paths); + mm_gdbus_modem_set_primary_sim_slot (ctx->skeleton, primary_sim_slot); + + /* If loading SIM slots is supported, we also expose already the primary active SIM object */ + if (primary_sim_slot) { + primary_sim = g_ptr_array_index (sim_slots, primary_sim_slot - 1); + if (primary_sim) + g_object_bind_property (primary_sim, MM_BASE_SIM_PATH, + ctx->skeleton, "sim", + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); + } + g_object_set (self, + MM_IFACE_MODEM_SIM, primary_sim, + MM_IFACE_MODEM_SIM_SLOTS, sim_slots, + NULL); + } + + /* Go on to next step */ + ctx->step++; + interface_initialization_step (task); +} + +static void modem_update_lock_info_ready (MMIfaceModem *self, GAsyncResult *res, GTask *task) @@ -5090,6 +5158,22 @@ interface_initialization_step (GTask *task) ctx->step++; /* fall-through */ + case INITIALIZATION_STEP_SIM_SLOTS: + /* If the modem doesn't need any SIM (not implemented by plugin, or not + * needed in CDMA-only modems), or if we don't know how to query + * for SIM slots */ + if (!mm_gdbus_modem_get_sim_slots (ctx->skeleton) && + !mm_iface_modem_is_cdma_only (self) && + MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots && + MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots_finish) { + MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots (MM_IFACE_MODEM (self), + (GAsyncReadyCallback)load_sim_slots_ready, + task); + return; + } + ctx->step++; + /* fall-through */ + case INITIALIZATION_STEP_UNLOCK_REQUIRED: /* Only check unlock required if we were previously not unlocked */ if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE) { @@ -5686,6 +5770,14 @@ iface_modem_init (gpointer g_iface) g_object_interface_install_property (g_iface, + g_param_spec_boxed (MM_IFACE_MODEM_SIM_SLOTS, + "SIM slots", + "SIM objects in SIM slots", + MM_TYPE_OBJECT_ARRAY, + G_PARAM_READWRITE)); + + g_object_interface_install_property + (g_iface, g_param_spec_enum (MM_IFACE_MODEM_STATE, "State", "State of the modem", diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h index 2df3b59c..0393155d 100644 --- a/src/mm-iface-modem.h +++ b/src/mm-iface-modem.h @@ -35,6 +35,7 @@ #define MM_IFACE_MODEM_DBUS_SKELETON "iface-modem-dbus-skeleton" #define MM_IFACE_MODEM_STATE "iface-modem-state" #define MM_IFACE_MODEM_SIM "iface-modem-sim" +#define MM_IFACE_MODEM_SIM_SLOTS "iface-modem-sim-slots" #define MM_IFACE_MODEM_BEARER_LIST "iface-modem-bearer-list" #define MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED "iface-modem-sim-hot-swap-supported" #define MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED "iface-modem-sim-hot-swap-configured" @@ -343,6 +344,16 @@ struct _MMIfaceModem { GAsyncResult *res, GError **error); + /* Create SIMs in all SIM slots */ + void (* load_sim_slots) (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* load_sim_slots_finish) (MMIfaceModem *self, + GAsyncResult *res, + GPtrArray **sim_slots, + guint *primary_sim_slot, + GError **error); + /* Create bearer */ void (*create_bearer) (MMIfaceModem *self, MMBearerProperties *properties, diff --git a/src/mm-private-boxed-types.c b/src/mm-private-boxed-types.c index 465649b5..a94dd2c4 100644 --- a/src/mm-private-boxed-types.c +++ b/src/mm-private-boxed-types.c @@ -171,6 +171,35 @@ mm_pointer_array_get_type (void) return g_define_type_id__volatile; } +static GPtrArray * +object_array_copy (GPtrArray *object_array) +{ + return g_ptr_array_ref (object_array); +} + +static void +object_array_free (GPtrArray *object_array) +{ + g_ptr_array_unref (object_array); +} + +GType +mm_object_array_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) { + GType g_define_type_id = + g_boxed_type_register_static (g_intern_static_string ("MMObjectArray"), + (GBoxedCopyFunc) object_array_copy, + (GBoxedFreeFunc) object_array_free); + + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + static void async_method_free (MMAsyncMethod *method) { diff --git a/src/mm-private-boxed-types.h b/src/mm-private-boxed-types.h index fcdcbb10..8a7d5fcb 100644 --- a/src/mm-private-boxed-types.h +++ b/src/mm-private-boxed-types.h @@ -34,6 +34,9 @@ GType mm_str_pair_array_get_type (void) G_GNUC_CONST; GType mm_pointer_array_get_type (void) G_GNUC_CONST; #define MM_TYPE_POINTER_ARRAY (mm_pointer_array_get_type ()) +GType mm_object_array_get_type (void) G_GNUC_CONST; +#define MM_TYPE_OBJECT_ARRAY (mm_object_array_get_type ()) + typedef struct { GCallback async; GCallback finish; |