modem: support SIM hot swap
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 * added SIM HOT SWAP boolean property 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
This commit is contained in:

committed by
Aleksander Morgado

parent
3047522b2e
commit
60f4f9e57d
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -114,6 +114,7 @@ enum {
|
||||
PROP_MODEM_MESSAGING_SMS_DEFAULT_STORAGE,
|
||||
PROP_MODEM_VOICE_CALL_LIST,
|
||||
PROP_MODEM_SIMPLE_STATUS,
|
||||
PROP_MODEM_SIM_HOT_SWAP_SUPPORTED,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
@@ -126,7 +127,9 @@ typedef struct _PortsContext PortsContext;
|
||||
struct _MMBroadbandModemPrivate {
|
||||
/* Broadband modem specific implementation */
|
||||
PortsContext *enabled_ports_ctx;
|
||||
PortsContext *sim_hot_swap_ports_ctx;
|
||||
gboolean modem_init_run;
|
||||
gboolean sim_hot_swap_supported;
|
||||
|
||||
/*<--- Modem interface --->*/
|
||||
/* Properties */
|
||||
@@ -8549,6 +8552,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;
|
||||
}
|
||||
|
||||
@@ -9667,6 +9675,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;
|
||||
@@ -10008,6 +10017,38 @@ initialize_step (InitializeContext *ctx)
|
||||
ctx);
|
||||
return;
|
||||
|
||||
case INITIALIZE_STEP_SIM_HOT_SWAP:
|
||||
{
|
||||
gboolean is_sim_hot_swap_supported = FALSE;
|
||||
|
||||
g_object_get (ctx->self,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED,
|
||||
&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 ("Creating PortsContext for SIM hot swap.");
|
||||
|
||||
ports = g_new0 (PortsContext, 1);
|
||||
ports->ref_count = 1;
|
||||
|
||||
if (!open_ports_enabling (ctx->self, ports, FALSE, &error)) {
|
||||
mm_warn ("Couldn't open ports during Modem SIM hot swap enabling: %s", error? error->message : "unknown reason");
|
||||
g_error_free (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));
|
||||
@@ -10028,11 +10069,35 @@ 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");
|
||||
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 (ctx->self,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED,
|
||||
&is_sim_hot_swap_supported,
|
||||
NULL);
|
||||
|
||||
if (reason == MM_MODEM_STATE_FAILED_REASON_SIM_MISSING &&
|
||||
is_sim_hot_swap_supported &&
|
||||
ctx->self->priv->sim_hot_swap_ports_ctx) {
|
||||
mm_info ("SIM is missing, but the modem supports SIM hot swap. 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.
|
||||
@@ -10045,6 +10110,7 @@ initialize_step (InitializeContext *ctx)
|
||||
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;
|
||||
@@ -10192,6 +10258,39 @@ mm_broadband_modem_create_device_identifier (MMBroadbandModem *self,
|
||||
MM_GDBUS_MODEM (MM_BROADBAND_MODEM (self)->priv->modem_dbus_skeleton))));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
static void
|
||||
after_hotswap_event_disable_ready (MMBaseModem *self,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
mm_base_modem_disable_finish (self, res, &error);
|
||||
if (error) {
|
||||
mm_err ("Disable modem error: %s", error->message);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
mm_base_modem_set_valid (MM_BASE_MODEM (self), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mm_broadband_modem_update_sim_hot_swap_detected (MMBroadbandModem *self)
|
||||
{
|
||||
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) after_hotswap_event_disable_ready,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModem *
|
||||
@@ -10323,6 +10422,9 @@ set_property (GObject *object,
|
||||
g_clear_object (&self->priv->modem_simple_status);
|
||||
self->priv->modem_simple_status = g_value_dup_object (value);
|
||||
break;
|
||||
case PROP_MODEM_SIM_HOT_SWAP_SUPPORTED:
|
||||
self->priv->sim_hot_swap_supported = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -10425,6 +10527,9 @@ get_property (GObject *object,
|
||||
case PROP_MODEM_SIMPLE_STATUS:
|
||||
g_value_set_object (value, self->priv->modem_simple_status);
|
||||
break;
|
||||
case PROP_MODEM_SIM_HOT_SWAP_SUPPORTED:
|
||||
g_value_set_boolean (value, self->priv->sim_hot_swap_supported);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -10453,6 +10558,7 @@ mm_broadband_modem_init (MMBroadbandModem *self)
|
||||
self->priv->modem_messaging_sms_default_storage = MM_SMS_STORAGE_UNKNOWN;
|
||||
self->priv->current_sms_mem1_storage = MM_SMS_STORAGE_UNKNOWN;
|
||||
self->priv->current_sms_mem2_storage = MM_SMS_STORAGE_UNKNOWN;
|
||||
self->priv->sim_hot_swap_supported = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -10907,4 +11013,8 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass)
|
||||
g_object_class_override_property (object_class,
|
||||
PROP_MODEM_SIMPLE_STATUS,
|
||||
MM_IFACE_MODEM_SIMPLE_STATUS);
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
PROP_MODEM_SIM_HOT_SWAP_SUPPORTED,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED);
|
||||
}
|
||||
|
@@ -127,5 +127,9 @@ 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_detected (MMBroadbandModem *self);
|
||||
|
||||
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_H */
|
||||
|
@@ -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
|
||||
|
@@ -3747,6 +3747,7 @@ typedef enum {
|
||||
INITIALIZATION_STEP_SUPPORTED_BANDS,
|
||||
INITIALIZATION_STEP_SUPPORTED_IP_FAMILIES,
|
||||
INITIALIZATION_STEP_POWER_STATE,
|
||||
INITIALIZATION_STEP_SIM_HOT_SWAP,
|
||||
INITIALIZATION_STEP_UNLOCK_REQUIRED,
|
||||
INITIALIZATION_STEP_SIM,
|
||||
INITIALIZATION_STEP_OWN_NUMBERS,
|
||||
@@ -4203,6 +4204,27 @@ 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,
|
||||
InitializationContext *ctx) {
|
||||
GError *error = NULL;
|
||||
|
||||
MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap_finish (self, res, &error);
|
||||
if (error) {
|
||||
mm_warn ("Iface modem: SIM hot swap setup failed: '%s'", error->message);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
mm_dbg ("Iface modem: SIM hot swap setup succeded");
|
||||
}
|
||||
|
||||
/* Go on to next step */
|
||||
ctx->step++;
|
||||
interface_initialization_step (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
interface_initialization_step (InitializationContext *ctx)
|
||||
{
|
||||
@@ -4544,6 +4566,18 @@ 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,
|
||||
ctx);
|
||||
return;
|
||||
}
|
||||
/* Fall down to next step */
|
||||
ctx->step++;
|
||||
|
||||
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 +4741,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 (ctx->self,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED,
|
||||
&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 {
|
||||
@@ -5119,6 +5168,13 @@ iface_modem_init (gpointer g_iface)
|
||||
"List of bearers handled by the modem",
|
||||
MM_TYPE_BEARER_LIST,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_interface_install_property
|
||||
(g_iface,
|
||||
g_param_spec_boolean (MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED,
|
||||
"Sim Hot Swap Supported",
|
||||
"Whether the modem supports sim hot swap or not.",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
@@ -32,10 +32,11 @@
|
||||
#define MM_IS_IFACE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_IFACE_MODEM))
|
||||
#define MM_IFACE_MODEM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_IFACE_MODEM, MMIfaceModem))
|
||||
|
||||
#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_BEARER_LIST "iface-modem-bearer-list"
|
||||
#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_BEARER_LIST "iface-modem-bearer-list"
|
||||
#define MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED "iface-modem-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);
|
||||
|
Reference in New Issue
Block a user