api,modem: new 'SimSlots' and 'PrimarySimSlot' properties

The 'SimSlots' property exposes an array of SIM object paths, with one
array item for each available SIM slot in the system. If a valid SIM
card is found in a given slot, the path of the SIM object will be
exposed in the array item; if no valid SIM card is found, the empty
object path ("/") will be exposed instead.

The 'PrimarySimSlot' property exposes which of the SIM slots available
in the system is the one configured as being primary. In a Multi-SIM
Single-Standby setup, the primary slot will be the one corresponding
to the single active SIM in the system. In a Multi-SIM Multi-Standby
setup, the primary slot will be the one configured to act as primary
(e.g. the one that will be used for the data connection) among all the
active SIM cards found.
This commit is contained in:
Aleksander Morgado
2020-08-01 09:59:27 +02:00
parent b2979c63eb
commit e7409b6898
12 changed files with 587 additions and 11 deletions

View File

@@ -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);

View File

@@ -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, },
@@ -569,6 +571,37 @@ mmcli_output_state (MMModemState state,
NULL);
}
/******************************************************************************/
/* (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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -217,10 +217,55 @@
<!--
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:

View File

@@ -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)
{

View File

@@ -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_ */

View File

@@ -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);
@@ -12712,6 +12722,10 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass)
PROP_MODEM_SIM,
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);

View File

@@ -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,
@@ -4400,6 +4401,73 @@ setup_sim_hot_swap_ready (MMIfaceModem *self,
interface_initialization_step (task);
}
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,
@@ -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) {
@@ -5684,6 +5768,14 @@ iface_modem_init (gpointer g_iface)
MM_TYPE_BASE_SIM,
G_PARAM_READWRITE));
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,

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -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;