aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/ublox/mm-broadband-modem-ublox.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/plugins/ublox/mm-broadband-modem-ublox.c b/plugins/ublox/mm-broadband-modem-ublox.c
index 2ae152fc..1c77faf7 100644
--- a/plugins/ublox/mm-broadband-modem-ublox.c
+++ b/plugins/ublox/mm-broadband-modem-ublox.c
@@ -1079,6 +1079,167 @@ common_voice_enable_disable_unsolicited_events (MMBroadbandModemUblox *self,
}
/*****************************************************************************/
+/* Hotplug configure (Modem interface) */
+
+typedef enum {
+ CIEV_SIM_STATUS_UNKNOWN = -1,
+ CIEV_SIM_STATUS_REMOVED,
+ CIEV_SIM_STATUS_INSERTED,
+} MMUbloxSimInsertStatus;
+
+static gboolean
+modem_setup_sim_hot_swap_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+ublox_ciev_unsolicited_handler (MMPortSerialAt *port,
+ GMatchInfo *match_info,
+ MMBroadbandModemUblox *self)
+{
+ gint sim_insert_status = CIEV_SIM_STATUS_UNKNOWN;
+
+ if (!mm_get_int_from_match_info (match_info, 1, &sim_insert_status)) {
+ mm_obj_dbg (self, "CIEV: unable to parse sim insert indication");
+ return;
+ }
+
+ mm_obj_info (self, "CIEV: sim hot swap detected '%d'", sim_insert_status);
+ if (sim_insert_status == CIEV_SIM_STATUS_INSERTED ||
+ sim_insert_status == CIEV_SIM_STATUS_REMOVED) {
+ mm_broadband_modem_sim_hot_swap_detected (MM_BROADBAND_MODEM (self));
+ } else {
+ mm_obj_warn (self, "(%s) CIEV: unable to determine sim insert status: %d",
+ mm_port_get_device (MM_PORT (port)),
+ sim_insert_status);
+ }
+}
+
+static void
+ublox_setup_ciev_handler (MMIfaceModem *self,
+ guint simind_idx)
+{
+ GRegex *pattern;
+ gchar *ciev_regex;
+ MMPortSerialAt *primary_port;
+ MMPortSerialAt *secondary_port;
+
+ primary_port = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
+ mm_obj_dbg (self, "setting up simind 'CIEV: %d' events handler", simind_idx);
+ ciev_regex = g_strdup_printf ("\\r\\n\\+CIEV: %d,([0-1]{1})\\r\\n", simind_idx);
+ pattern = g_regex_new (ciev_regex,
+ G_REGEX_RAW | G_REGEX_OPTIMIZE,
+ 0, NULL);
+ g_assert (pattern);
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ primary_port,
+ pattern,
+ (MMPortSerialAtUnsolicitedMsgFn) ublox_ciev_unsolicited_handler,
+ self,
+ NULL);
+
+ secondary_port = mm_base_modem_get_port_secondary (MM_BASE_MODEM (self));
+ if (secondary_port)
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ secondary_port,
+ pattern,
+ (MMPortSerialAtUnsolicitedMsgFn) ublox_ciev_unsolicited_handler,
+ self,
+ NULL);
+
+ g_regex_unref (pattern);
+ g_free (ciev_regex);
+}
+
+static void
+process_cind_verbosity_response (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ mm_base_modem_at_command_finish (self, res, &error);
+
+ if (error) {
+ mm_obj_warn (self, "CIND: verbose mode is not configured: %s", error->message);
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ mm_obj_info (self, "CIND unsolicited response codes processing verbosity configured successfully");
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+typedef struct {
+ gchar *desc;
+ guint idx;
+ gint min;
+ gint max;
+} CindResponse;
+
+static void
+cind_simind_format_check_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GHashTable *indicators = NULL;
+ GError *error = NULL;
+ const gchar *result;
+ CindResponse *r;
+
+ result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
+ if (error ||
+ !(indicators = mm_3gpp_parse_cind_test_response (result, &error))) {
+ mm_obj_dbg (self, "+CIND check failed: %s", error->message);
+ g_prefix_error (&error, "CIND check failed: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ r = g_hash_table_lookup (indicators, "simind");
+ if (r) {
+ mm_obj_dbg (self, "simind CIEV indications are supported, indication order number: %d", r->idx);
+ ublox_setup_ciev_handler (MM_IFACE_MODEM (self), r->idx);
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CMER=1,0,0,1,0",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback) process_cind_verbosity_response,
+ task);
+ } else {
+ mm_obj_dbg (self, "simind CIEV indications are not supported");
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "simind CIEV indications are not supported");
+ g_object_unref (task);
+ }
+ g_hash_table_destroy (indicators);
+}
+
+static void
+modem_setup_sim_hot_swap (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CIND=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback) cind_simind_format_check_ready,
+ task);
+}
+
+/*****************************************************************************/
/* Enabling unsolicited events (Voice interface) */
static gboolean
@@ -1811,6 +1972,8 @@ mm_broadband_modem_ublox_new (const gchar *device,
MM_BASE_MODEM_PLUGIN, plugin,
MM_BASE_MODEM_VENDOR_ID, vendor_id,
MM_BASE_MODEM_PRODUCT_ID, product_id,
+ MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
+ MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, FALSE,
/* Generic bearer (TTY) and u-blox bearer (NET) supported */
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
MM_BASE_MODEM_DATA_TTY_SUPPORTED, TRUE,
@@ -1867,6 +2030,8 @@ iface_modem_init (MMIfaceModem *iface)
iface->load_current_bands_finish = load_current_bands_finish;
iface->set_current_bands = set_current_bands;
iface->set_current_bands_finish = common_set_current_modes_bands_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