[PATCH] Core logic to support SIM hot swap

Carlo Lobrano c.lobrano at gmail.com
Thu Jun 30 11:44:46 UTC 2016


Hi all,

sorry but I sent the previous email before completing it. This
proposal is based on two patches.
The first, in the previous e-mail, adds the core logic for modems that
support SIM hot swap,
The second in this e-mail, is the plugin side implementation for a Telit modem.

Carlo

---

MMBroadbandModemTelit:
 * added SIM_HOT_SWAP property and updated init function accordingly
 * added function to enable QSS unsolicited
 * added QSS unsolicited handler
---
 plugins/dell/mm-plugin-dell.c            |   3 +-
 plugins/telit/mm-broadband-modem-telit.c | 185 ++++++++++++++++++++++++++++++-
 plugins/telit/mm-broadband-modem-telit.h |   7 +-
 plugins/telit/mm-plugin-telit.c          |   3 +-
 4 files changed, 191 insertions(+), 4 deletions(-)

diff --git a/plugins/dell/mm-plugin-dell.c b/plugins/dell/mm-plugin-dell.c
index 2ed4375..9275a04 100644
--- a/plugins/dell/mm-plugin-dell.c
+++ b/plugins/dell/mm-plugin-dell.c
@@ -424,7 +424,8 @@ create_modem (MMPlugin *self,
                                                             drivers,

mm_plugin_get_name (self),
                                                             vendor,
-                                                            product));
+                                                            product,
+                                                            TRUE /*
SIM hot swap supported */));
     }

     mm_dbg ("Dell-branded generic modem found...");
diff --git a/plugins/telit/mm-broadband-modem-telit.c
b/plugins/telit/mm-broadband-modem-telit.c
index 8baf2cf..b8ca965 100644
--- a/plugins/telit/mm-broadband-modem-telit.c
+++ b/plugins/telit/mm-broadband-modem-telit.c
@@ -42,6 +42,131 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemTelit,
mm_broadband_modem_telit, MM_TYPE
                         G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM,
iface_modem_init)
                         G_IMPLEMENT_INTERFACE
(MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init));

+
+struct _MMBroadbandModemTelitPrivate  {
+    gboolean is_sim_hot_swap_supported;
+    GAsyncReadyCallback sim_swap_callback;
+};
+
+enum {
+    PROP_FIRST,
+    PROP_IS_SIM_HOT_SWAP_SUPPORTED,
+    PROP_LAST
+};
+
+/*****************************************************************************/
+/* Setup SIM hot swap (Modem interface) */
+
+static void
+telit_qss_unsolicited_handler (MMPortSerialAt *port,
+                               GMatchInfo *match_info,
+                               MMBroadbandModemTelit *self)
+{
+    guint qss;
+    gboolean is_sim_missing;
+
+    if (!mm_get_uint_from_match_info (match_info, 1, &qss))
+        return;
+
+    switch(qss) {
+        case 0:
+            mm_info("QSS: SIM removed");
+            break;
+        case 1:
+            mm_info("QSS: SIM inserted");
+            break;
+        case 2:
+            mm_info("QSS: SIM inserted and PIN unlocked");
+            break;
+        case 3:
+            mm_info("QSS: SIM inserted and PIN locked");
+            break;
+        default:
+            mm_warn("QSS: unknown QSS value %d", qss);
+            break;
+    }
+
+    is_sim_missing = (qss == 0) ? TRUE : FALSE;
+    mm_broadband_modem_update_sim_hot_swap_status (MM_BROADBAND_MODEM
(self), is_sim_missing);
+}
+
+typedef struct {
+    MMBroadbandModemTelit *self;
+    GSimpleAsyncResult *result;
+} ToggleQssUnsolicitedContext;
+
+static void
+toggle_qss_unsolicited_context_complete_and_free
(ToggleQssUnsolicitedContext *ctx)
+{
+    g_simple_async_result_complete (ctx->result);
+    g_object_unref (ctx->result);
+    g_object_unref (ctx->self);
+    g_slice_free (ToggleQssUnsolicitedContext, ctx);
+}
+
+static gboolean
+modem_setup_sim_hot_swap_finish (MMIfaceModem *self,
+                                 GAsyncResult *res,
+                                 GError **error)
+{
+    return !g_simple_async_result_propagate_error
(G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+telit_qss_toggle_ready (MMBaseModem *self,
+                        GAsyncResult *res,
+                        ToggleQssUnsolicitedContext *ctx)
+{
+    GError *error = NULL;
+
+    mm_base_modem_at_command_finish (self, res, &error);
+    if (error) {
+        mm_warn ("Enable QSS failed: %s", error->message);
+        g_simple_async_result_set_error (ctx->result,
+                                         MM_CORE_ERROR,
+                                         MM_CORE_ERROR_FAILED,
+                                         "Could not enable QSS");
+    } else {
+        mm_port_serial_at_add_unsolicited_msg_handler (
+            mm_base_modem_peek_port_secondary (MM_BASE_MODEM (ctx->self)),
+            g_regex_new ("#QSS:\\s*([0-3])\\r\\n", G_REGEX_RAW, 0, NULL),
+            (MMPortSerialAtUnsolicitedMsgFn)telit_qss_unsolicited_handler,
+            ctx->self,
+            NULL);
+        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+    }
+
+    toggle_qss_unsolicited_context_complete_and_free (ctx);
+}
+
+
+static void
+modem_setup_sim_hot_swap (MMIfaceModem *self,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+    ToggleQssUnsolicitedContext *ctx;
+
+    mm_dbg ("Telit: enabling QSS");
+
+    ctx = g_slice_new0 (ToggleQssUnsolicitedContext);
+    ctx->self = g_object_ref (MM_BROADBAND_MODEM_TELIT (self));
+    ctx->result = g_simple_async_result_new (G_OBJECT (self),
+                                             callback,
+                                             user_data,
+                                             modem_setup_sim_hot_swap);
+
+    mm_base_modem_at_command_full (MM_BASE_MODEM (self),
+                                   mm_base_modem_peek_port_secondary
(MM_BASE_MODEM (self)),
+                                   "#QSS=1",
+                                   3,
+                                   FALSE,
+                                   FALSE, /* raw */
+                                   NULL, /* cancellable */
+                                   (GAsyncReadyCallback)
telit_qss_toggle_ready,
+                                   ctx);
+}
+
 /*****************************************************************************/
 /* Set current bands (Modem interface) */

@@ -1009,7 +1134,8 @@ mm_broadband_modem_telit_new (const gchar *device,
                              const gchar **drivers,
                              const gchar *plugin,
                              guint16 vendor_id,
-                             guint16 product_id)
+                             guint16 product_id,
+                             gboolean is_sim_hot_swap_supported)
 {
     return g_object_new (MM_TYPE_BROADBAND_MODEM_TELIT,
                          MM_BASE_MODEM_DEVICE, device,
@@ -1017,12 +1143,17 @@ mm_broadband_modem_telit_new (const gchar *device,
                          MM_BASE_MODEM_PLUGIN, plugin,
                          MM_BASE_MODEM_VENDOR_ID, vendor_id,
                          MM_BASE_MODEM_PRODUCT_ID, product_id,
+                         IS_SIM_HOT_SWAP_SUPPORTED_PROPERTY,
is_sim_hot_swap_supported,
                          NULL);
 }

 static void
 mm_broadband_modem_telit_init (MMBroadbandModemTelit *self)
 {
+    /* Initialize private data */
+    self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                              MM_TYPE_BROADBAND_MODEM_TELIT,
+                                              MMBroadbandModemTelitPrivate);
 }

 static void
@@ -1052,6 +1183,8 @@ iface_modem_init (MMIfaceModem *iface)
     iface->load_current_modes_finish = load_current_modes_finish;
     iface->set_current_modes = set_current_modes;
     iface->set_current_modes_finish = set_current_modes_finish;
+    iface->setup_sim_hot_swap = modem_setup_sim_hot_swap;
+    iface->setup_sim_hot_swap_finish = modem_setup_sim_hot_swap_finish;
 }

 static void
@@ -1062,6 +1195,56 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
 }

 static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+    MMBroadbandModemTelit *self = MM_BROADBAND_MODEM_TELIT (object);
+
+    switch (prop_id) {
+    case PROP_IS_SIM_HOT_SWAP_SUPPORTED:
+        self->priv->is_sim_hot_swap_supported = g_value_get_boolean (value);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+    MMBroadbandModemTelit *self = MM_BROADBAND_MODEM_TELIT (object);
+
+    switch (prop_id) {
+    case PROP_IS_SIM_HOT_SWAP_SUPPORTED:
+        g_value_set_boolean (value, self->priv->is_sim_hot_swap_supported);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
 mm_broadband_modem_telit_class_init (MMBroadbandModemTelitClass *klass)
 {
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof
(MMBroadbandModemTelitPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    g_object_class_install_property (object_class,
PROP_IS_SIM_HOT_SWAP_SUPPORTED,
+        g_param_spec_boolean (IS_SIM_HOT_SWAP_SUPPORTED_PROPERTY,
+                              "IsSimHotSwapSupported",
+                              "Whether the modem supports sim hot
swap or not.",
+                              TRUE,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 }
diff --git a/plugins/telit/mm-broadband-modem-telit.h
b/plugins/telit/mm-broadband-modem-telit.h
index 50e6365..37e2f21 100644
--- a/plugins/telit/mm-broadband-modem-telit.h
+++ b/plugins/telit/mm-broadband-modem-telit.h
@@ -27,11 +27,15 @@
 #define MM_IS_BROADBAND_MODEM_TELIT_CLASS(klass)
(G_TYPE_CHECK_CLASS_TYPE ((klass),  MM_TYPE_BROADBAND_MODEM_TELIT))
 #define MM_BROADBAND_MODEM_TELIT_GET_CLASS(obj)
(G_TYPE_INSTANCE_GET_CLASS ((obj),  MM_TYPE_BROADBAND_MODEM_TELIT,
MMBroadbandModemTelitClass))

+#define IS_SIM_HOT_SWAP_SUPPORTED_PROPERTY "is-sim-hot-swap-supported"
+
 typedef struct _MMBroadbandModemTelit MMBroadbandModemTelit;
+typedef struct _MMBroadbandModemTelitPrivate MMBroadbandModemTelitPrivate;
 typedef struct _MMBroadbandModemTelitClass MMBroadbandModemTelitClass;

 struct _MMBroadbandModemTelit {
     MMBroadbandModem parent;
+    MMBroadbandModemTelitPrivate *priv;
 };

 struct _MMBroadbandModemTelitClass{
@@ -44,6 +48,7 @@ MMBroadbandModemTelit *mm_broadband_modem_telit_new
(const gchar *device,
                                                      const gchar **drivers,
                                                      const gchar *plugin,
                                                      guint16 vendor_id,
-                                                     guint16 product_id);
+                                                     guint16 product_id,
+                                                     gboolean
is_sim_hot_swap_supported);

 #endif /* MM_BROADBAND_MODEM_TELIT_H */
diff --git a/plugins/telit/mm-plugin-telit.c b/plugins/telit/mm-plugin-telit.c
index 5a44ba6..b9506da 100644
--- a/plugins/telit/mm-plugin-telit.c
+++ b/plugins/telit/mm-plugin-telit.c
@@ -48,7 +48,8 @@ create_modem (MMPlugin *self,
                                                         drivers,

mm_plugin_get_name (self),
                                                         vendor,
-                                                        product));
+                                                        product,
+                                                        TRUE /*
support sim hot swap */));
 }

 /*****************************************************************************/

On 30 June 2016 at 13:36, Carlo Lobrano <c.lobrano at gmail.com> wrote:
> BaseModem
>   added reprobe property.
>
> MMDevice
>   added logic to recreate the modem if it is set invalid and "to reprobe"
>
> MMBroadbandModem
>  * added initialization step for SIM hot swap:
>     1. keep dedicated ports open to listen to modem's unsolicited
>     2. dedicated error management in case of initialization failure due to SIM missing
>  * added function to be called in order to act upon SIM insertion/removal:
>     1. close dedicated ports
>     2. set the modem to be reprobed
>     3. disable modem
>
> MMIfaceModem
>  * added initialization step for SIM hot swap, if supported by the plugin
>  * dedicated error management in case of initialization failure due to SIM missing
> ---
>  src/mm-base-modem.c      |  26 ++++++++++
>  src/mm-base-modem.h      |   4 ++
>  src/mm-broadband-modem.c | 126 ++++++++++++++++++++++++++++++++++++++++-------
>  src/mm-broadband-modem.h |   5 ++
>  src/mm-device.c          |  15 ++++++
>  src/mm-iface-modem.c     |  41 +++++++++++++++
>  src/mm-iface-modem.h     |   9 ++++
>  7 files changed, 209 insertions(+), 17 deletions(-)
>
> diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
> index 9cd7c5f..ede014b 100644
> --- a/src/mm-base-modem.c
> +++ b/src/mm-base-modem.c
> @@ -47,6 +47,7 @@ enum {
>      PROP_VENDOR_ID,
>      PROP_PRODUCT_ID,
>      PROP_CONNECTION,
> +    PROP_REPROBE,
>      PROP_LAST
>  };
>
> @@ -70,6 +71,7 @@ struct _MMBaseModemPrivate {
>
>      gboolean hotplugged;
>      gboolean valid;
> +    gboolean reprobe;
>
>      guint max_timeouts;
>
> @@ -392,6 +394,24 @@ mm_base_modem_set_valid (MMBaseModem *self,
>      }
>  }
>
> +void
> +mm_base_modem_set_reprobe (MMBaseModem *self,
> +                           gboolean reprobe)
> +{
> +    g_return_if_fail (MM_IS_BASE_MODEM (self));
> +
> +    self->priv->reprobe = reprobe;
> +}
> +
> +gboolean
> +mm_base_modem_get_reprobe (MMBaseModem *self)
> +{
> +    g_return_val_if_fail (MM_IS_BASE_MODEM (self), FALSE);
> +
> +    return self->priv->reprobe;
> +}
> +
> +
>  gboolean
>  mm_base_modem_get_valid (MMBaseModem *self)
>  {
> @@ -1295,6 +1315,9 @@ set_property (GObject *object,
>      case PROP_VALID:
>          mm_base_modem_set_valid (self, g_value_get_boolean (value));
>          break;
> +    case PROP_REPROBE:
> +        mm_base_modem_set_reprobe (self, g_value_get_boolean (value));
> +        break;
>      case PROP_MAX_TIMEOUTS:
>          self->priv->max_timeouts = g_value_get_uint (value);
>          break;
> @@ -1338,6 +1361,9 @@ get_property (GObject *object,
>      case PROP_VALID:
>          g_value_set_boolean (value, self->priv->valid);
>          break;
> +    case PROP_REPROBE:
> +        g_value_set_boolean (value, self->priv->reprobe);
> +        break;
>      case PROP_MAX_TIMEOUTS:
>          g_value_set_uint (value, self->priv->max_timeouts);
>          break;
> diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h
> index 3c0d16f..c4bcdce 100644
> --- a/src/mm-base-modem.h
> +++ b/src/mm-base-modem.h
> @@ -166,6 +166,10 @@ void     mm_base_modem_set_valid    (MMBaseModem *self,
>                                       gboolean valid);
>  gboolean mm_base_modem_get_valid    (MMBaseModem *self);
>
> +void     mm_base_modem_set_reprobe (MMBaseModem *self,
> +                                    gboolean reprobe);
> +gboolean mm_base_modem_get_reprobe (MMBaseModem *self);
> +
>  const gchar  *mm_base_modem_get_device  (MMBaseModem *self);
>  const gchar **mm_base_modem_get_drivers (MMBaseModem *self);
>  const gchar  *mm_base_modem_get_plugin  (MMBaseModem *self);
> diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
> index e1fd7ca..38fabed 100644
> --- a/src/mm-broadband-modem.c
> +++ b/src/mm-broadband-modem.c
> @@ -124,6 +124,7 @@ typedef struct _PortsContext PortsContext;
>  struct _MMBroadbandModemPrivate {
>      /* Broadband modem specific implementation */
>      PortsContext *enabled_ports_ctx;
> +    PortsContext *sim_hot_swap_ports_ctx;
>      gboolean modem_init_run;
>
>      /*<--- Modem interface --->*/
> @@ -8317,6 +8318,11 @@ disabling_stopped (MMBroadbandModem *self,
>          ports_context_unref (self->priv->enabled_ports_ctx);
>          self->priv->enabled_ports_ctx = NULL;
>      }
> +
> +    if (self->priv->sim_hot_swap_ports_ctx) {
> +        ports_context_unref (self->priv->sim_hot_swap_ports_ctx);
> +        self->priv->sim_hot_swap_ports_ctx = NULL;
> +    }
>      return TRUE;
>  }
>
> @@ -9435,6 +9441,7 @@ typedef enum {
>      INITIALIZE_STEP_IFACE_SIGNAL,
>      INITIALIZE_STEP_IFACE_OMA,
>      INITIALIZE_STEP_IFACE_FIRMWARE,
> +    INITIALIZE_STEP_SIM_HOT_SWAP,
>      INITIALIZE_STEP_IFACE_SIMPLE,
>      INITIALIZE_STEP_LAST,
>  } InitializeStep;
> @@ -9776,6 +9783,38 @@ initialize_step (InitializeContext *ctx)
>                                              ctx);
>          return;
>
> +    case INITIALIZE_STEP_SIM_HOT_SWAP:
> +        {
> +            gboolean is_sim_hot_swap_supported = FALSE;
> +
> +            g_object_get(MM_BASE_MODEM (ctx->self),
> +                         IS_SIM_HOT_SWAP_SUPPORTED_PROPERTY,
> +                         &is_sim_hot_swap_supported,
> +                         NULL);
> +
> +            if (!is_sim_hot_swap_supported) {
> +                ctx->self->priv->sim_hot_swap_ports_ctx = NULL;
> +            } else {
> +                PortsContext *ports;
> +                GError *error = NULL;
> +
> +                mm_dbg ("Modem supports SIM hot swap. Opening dedicated ports.");
> +
> +                ports = g_new0 (PortsContext, 1);
> +                ports->ref_count = 1;
> +
> +                if (!open_ports_enabling (ctx->self, ports, FALSE, &error)) {
> +                    g_prefix_error (&error, "Couldn't open ports during Modem SIM hot swap enabling: ");
> +                    g_simple_async_result_take_error (ctx->result, error);
> +                } else {
> +                    ctx->self->priv->sim_hot_swap_ports_ctx = ports_context_ref (ports);
> +                    ports_context_unref (ports);
> +                }
> +            }
> +        }
> +        /* Fall down to next step */
> +        ctx->step++;
> +
>      case INITIALIZE_STEP_IFACE_SIMPLE:
>          if (ctx->self->priv->modem_state != MM_MODEM_STATE_FAILED)
>              mm_iface_modem_simple_initialize (MM_IFACE_MODEM_SIMPLE (ctx->self));
> @@ -9796,23 +9835,45 @@ initialize_step (InitializeContext *ctx)
>                                                   "cannot fully initialize");
>              } else {
>                  /* Fatal SIM, firmware, or modem failure :-( */
> -                g_simple_async_result_set_error (ctx->result,
> -                                                 MM_CORE_ERROR,
> -                                                 MM_CORE_ERROR_WRONG_STATE,
> -                                                 "Modem is unusable, "
> -                                                 "cannot fully initialize");
> -                /* Ensure we only leave the Modem, OMA, and Firmware interfaces
> -                 * around.  A failure could be caused by firmware issues, which
> -                 * a firmware update, switch, or provisioning could fix.
> -                 */
> -                mm_iface_modem_3gpp_shutdown (MM_IFACE_MODEM_3GPP (ctx->self));
> -                mm_iface_modem_3gpp_ussd_shutdown (MM_IFACE_MODEM_3GPP_USSD (ctx->self));
> -                mm_iface_modem_cdma_shutdown (MM_IFACE_MODEM_CDMA (ctx->self));
> -                mm_iface_modem_location_shutdown (MM_IFACE_MODEM_LOCATION (ctx->self));
> -                mm_iface_modem_messaging_shutdown (MM_IFACE_MODEM_MESSAGING (ctx->self));
> -                mm_iface_modem_voice_shutdown (MM_IFACE_MODEM_VOICE (ctx->self));
> -                mm_iface_modem_time_shutdown (MM_IFACE_MODEM_TIME (ctx->self));
> -                mm_iface_modem_simple_shutdown (MM_IFACE_MODEM_SIMPLE (ctx->self));
> +                gboolean is_sim_hot_swap_supported = FALSE;
> +                MMModemStateFailedReason reason =
> +                    mm_gdbus_modem_get_state_failed_reason (
> +                        (MmGdbusModem*)ctx->self->priv->modem_dbus_skeleton);
> +
> +                g_object_get(MM_BASE_MODEM (ctx->self),
> +                             IS_SIM_HOT_SWAP_SUPPORTED_PROPERTY,
> +                             &is_sim_hot_swap_supported,
> +                             NULL);
> +
> +                if (reason == MM_MODEM_STATE_FAILED_REASON_SIM_MISSING &&
> +                    is_sim_hot_swap_supported) {
> +                        mm_info("SIM is missing, but the modem supports SIM hot insertion. Waiting for SIM...");
> +                        g_simple_async_result_set_error (ctx->result,
> +                                                         MM_CORE_ERROR,
> +                                                         MM_CORE_ERROR_WRONG_STATE,
> +                                                         "Modem is unusable due to SIM missing, "
> +                                                         "cannot fully initialize, "
> +                                                         "waiting for SIM insertion.");
> +                } else {
> +                    mm_dbg ("SIM is missing and Modem does not support SIM Hot Swap");
> +                    g_simple_async_result_set_error (ctx->result,
> +                                                     MM_CORE_ERROR,
> +                                                     MM_CORE_ERROR_WRONG_STATE,
> +                                                     "Modem is unusable, "
> +                                                     "cannot fully initialize");
> +                    /* Ensure we only leave the Modem, OMA, and Firmware interfaces
> +                     * around.  A failure could be caused by firmware issues, which
> +                     * a firmware update, switch, or provisioning could fix.
> +                     */
> +                    mm_iface_modem_3gpp_shutdown (MM_IFACE_MODEM_3GPP (ctx->self));
> +                    mm_iface_modem_3gpp_ussd_shutdown (MM_IFACE_MODEM_3GPP_USSD (ctx->self));
> +                    mm_iface_modem_cdma_shutdown (MM_IFACE_MODEM_CDMA (ctx->self));
> +                    mm_iface_modem_location_shutdown (MM_IFACE_MODEM_LOCATION (ctx->self));
> +                    mm_iface_modem_messaging_shutdown (MM_IFACE_MODEM_MESSAGING (ctx->self));
> +                    mm_iface_modem_voice_shutdown (MM_IFACE_MODEM_VOICE (ctx->self));
> +                    mm_iface_modem_time_shutdown (MM_IFACE_MODEM_TIME (ctx->self));
> +                    mm_iface_modem_simple_shutdown (MM_IFACE_MODEM_SIMPLE (ctx->self));
> +                }
>              }
>              initialize_context_complete_and_free (ctx);
>              return;
> @@ -9960,6 +10021,37 @@ mm_broadband_modem_create_device_identifier (MMBroadbandModem *self,
>                      MM_GDBUS_MODEM (MM_BROADBAND_MODEM (self)->priv->modem_dbus_skeleton))));
>  }
>
> +
> +/*****************************************************************************/
> +static void
> +disable_ready (MMBaseModem *self,
> +               GAsyncResult *res,
> +               gpointer user_data)
> +{
> +    GError *error = NULL;
> +    if (!mm_base_modem_disable_finish (self, res, &error)) {
> +        mm_err ("Disable modem error: %s", error->message);
> +    } else {
> +      mm_base_modem_set_valid (MM_BASE_MODEM (self), FALSE);
> +    }
> +}
> +
> +
> +void mm_broadband_modem_update_sim_hot_swap_status (MMBroadbandModem *self,
> +                                                    gboolean is_sim_missing)
> +{
> +    if (self->priv->sim_hot_swap_ports_ctx) {
> +        mm_dbg ("Releasing SIM hot swap ports context");
> +        ports_context_unref (self->priv->sim_hot_swap_ports_ctx);
> +        self->priv->sim_hot_swap_ports_ctx = NULL;
> +    }
> +
> +    mm_base_modem_set_reprobe (MM_BASE_MODEM (self), TRUE);
> +    mm_base_modem_disable (MM_BASE_MODEM (self),
> +                           (GAsyncReadyCallback)disable_ready,
> +                           NULL);
> +}
> +
>  /*****************************************************************************/
>
>  MMBroadbandModem *
> diff --git a/src/mm-broadband-modem.h b/src/mm-broadband-modem.h
> index 93ffeb5..ca5bab3 100644
> --- a/src/mm-broadband-modem.h
> +++ b/src/mm-broadband-modem.h
> @@ -127,5 +127,10 @@ gboolean mm_broadband_modem_lock_sms_storages_finish (MMBroadbandModem *self,
>  void     mm_broadband_modem_unlock_sms_storages      (MMBroadbandModem *self,
>                                                        gboolean mem1,
>                                                        gboolean mem2);
> +/* Helper to update SIM hot swap */
> +void mm_broadband_modem_update_sim_hot_swap_status (MMBroadbandModem *self,
> +                                                    gboolean is_sim_missing);
> +
> +
>
>  #endif /* MM_BROADBAND_MODEM_H */
> diff --git a/src/mm-device.c b/src/mm-device.c
> index 2456cc8..abc8f30 100644
> --- a/src/mm-device.c
> +++ b/src/mm-device.c
> @@ -489,8 +489,23 @@ modem_valid (MMBaseModem *modem,
>               MMDevice    *self)
>  {
>      if (!mm_base_modem_get_valid (modem)) {
> +        GDBusObjectManagerServer *object_manager = self->priv->object_manager;
> +
>          /* Modem no longer valid */
>          mm_device_remove_modem (self);
> +
> +        if (mm_base_modem_get_reprobe (modem)) {
> +            GError *error = NULL;
> +
> +            if (!mm_device_create_modem (self, object_manager, &error)) {
> +                 mm_warn ("Could not recreate modem for device at '%s': %s",
> +                         mm_device_get_path(self),
> +                         error ? error->message : "unknown");
> +                g_error_free (error);
> +            } else {
> +                mm_dbg ("Modem recreated for device '%s'", mm_device_get_path(self));
> +            }
> +        }
>      } else {
>          /* Modem now valid, export it, but only if we really have it around.
>           * It may happen that the initialization sequence fails because the
> diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
> index 516ed78..9aa6df8 100644
> --- a/src/mm-iface-modem.c
> +++ b/src/mm-iface-modem.c
> @@ -3745,6 +3745,7 @@ typedef enum {
>      INITIALIZATION_STEP_DEVICE_ID,
>      INITIALIZATION_STEP_SUPPORTED_MODES,
>      INITIALIZATION_STEP_SUPPORTED_BANDS,
> +    INITIALIZATION_STEP_SIM_HOT_SWAP,
>      INITIALIZATION_STEP_SUPPORTED_IP_FAMILIES,
>      INITIALIZATION_STEP_POWER_STATE,
>      INITIALIZATION_STEP_UNLOCK_REQUIRED,
> @@ -4203,6 +4204,22 @@ load_current_bands_ready (MMIfaceModem *self,
>      interface_initialization_step (ctx);
>  }
>
> +/*****************************************************************************/
> +/* Setup SIM hot swap (Modem interface) */
> +static void
> +setup_sim_hot_swap_ready (MMIfaceModem *self,
> +                          GAsyncResult *res,
> +                          gpointer user_data) {
> +    GError *error = NULL;
> +
> +    MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap_finish (self, res, &error);
> +    if (error)
> +        mm_warn ("SIM hot swap setup failed: '%s'", error->message);
> +    else
> +        mm_dbg ("SIM hot swap setup succeded");
> +}
> +
>  static void
>  interface_initialization_step (InitializationContext *ctx)
>  {
> @@ -4544,6 +4561,15 @@ interface_initialization_step (InitializationContext *ctx)
>          /* Fall down to next step */
>          ctx->step++;
>
> +    case INITIALIZATION_STEP_SIM_HOT_SWAP:
> +        if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->setup_sim_hot_swap &&
> +            MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->setup_sim_hot_swap_finish) {
> +            MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->setup_sim_hot_swap (
> +                MM_IFACE_MODEM (ctx->self),
> +                (GAsyncReadyCallback) setup_sim_hot_swap_ready,
> +                NULL);
> +        }
> +
>      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) {
> @@ -4707,6 +4733,21 @@ interface_initialization_step (InitializationContext *ctx)
>                            ctx->self);
>
>          if (ctx->fatal_error) {
> +            if (g_error_matches (ctx->fatal_error,
> +                                 MM_MOBILE_EQUIPMENT_ERROR,
> +                                 MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED)) {
> +                gboolean is_sim_hot_swap_supported = FALSE;
> +
> +                g_object_get(MM_BASE_MODEM (ctx->self),
> +                             IS_SIM_HOT_SWAP_SUPPORTED_PROPERTY,
> +                             &is_sim_hot_swap_supported,
> +                             NULL);
> +
> +                if(is_sim_hot_swap_supported) {
> +                    mm_iface_modem_update_failed_state (ctx->self,
> +                                                        MM_MODEM_STATE_FAILED_REASON_SIM_MISSING);
> +                }
> +            }
>              g_simple_async_result_take_error (ctx->result, ctx->fatal_error);
>              ctx->fatal_error = NULL;
>          } else {
> diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
> index 74ea9f9..eabb0be 100644
> --- a/src/mm-iface-modem.h
> +++ b/src/mm-iface-modem.h
> @@ -36,6 +36,7 @@
>  #define MM_IFACE_MODEM_STATE         "iface-modem-state"
>  #define MM_IFACE_MODEM_SIM           "iface-modem-sim"
>  #define MM_IFACE_MODEM_BEARER_LIST   "iface-modem-bearer-list"
> +#define IS_SIM_HOT_SWAP_SUPPORTED_PROPERTY "is-sim-hot-swap-supported"
>
>  typedef struct _MMIfaceModem MMIfaceModem;
>
> @@ -327,6 +328,14 @@ struct _MMIfaceModem {
>      MMBaseBearer * (*create_bearer_finish) (MMIfaceModem *self,
>                                              GAsyncResult *res,
>                                              GError **error);
> +    /* Setup SIM hot swap */
> +    void (*setup_sim_hot_swap) (MMIfaceModem *self,
> +                                GAsyncReadyCallback callback,
> +                                gpointer user_data);
> +
> +    gboolean (*setup_sim_hot_swap_finish) (MMIfaceModem *self,
> +                                            GAsyncResult *res,
> +                                            GError **error);
>  };
>
>  GType mm_iface_modem_get_type (void);
> --
> 2.7.4
>


More information about the ModemManager-devel mailing list