aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/mmcli-modem.c2
-rw-r--r--cli/mmcli-output.c35
-rw-r--r--cli/mmcli-output.h20
-rw-r--r--docs/reference/libmm-glib/libmm-glib-sections.txt11
-rw-r--r--introspection/org.freedesktop.ModemManager1.Modem.xml47
-rw-r--r--libmm-glib/mm-modem.c316
-rw-r--r--libmm-glib/mm-modem.h16
-rw-r--r--src/mm-broadband-modem.c14
-rw-r--r--src/mm-iface-modem.c94
-rw-r--r--src/mm-iface-modem.h11
-rw-r--r--src/mm-private-boxed-types.c29
-rw-r--r--src/mm-private-boxed-types.h3
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;