For some modem like ZTE MF180/190, we need to do some
polling to check SIM state when it returns +CME ERROR: 14 busy.
---
drivers/atmodem/sim.c | 59 +++++++++++++++++++++++++++++++++++++++---------
1 files changed, 48 insertions(+), 11 deletions(-)
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index c51b1d4..a23738b 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -51,6 +51,8 @@ struct sim_data {
GAtChat *chat;
unsigned int vendor;
guint ready_id;
+ guint poll_source;
+ guint poll_count;
};
static const char *crsm_prefix[] = { "+CRSM:", NULL };
@@ -856,6 +858,8 @@ static void at_pin_retries_query(struct ofono_sim *sim,
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
+static gboolean sim_state_check(gpointer user_data);
+
static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -874,9 +878,22 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer
user_data)
else
decode_at_error(&error, final);
- if (!ok) {
+ switch (error.type) {
+ case OFONO_ERROR_TYPE_NO_ERROR:
+ break;
+ case OFONO_ERROR_TYPE_CME:
+ /* Check for SIM busy - try again later */
+ if (error.error == 14) {
+ if (sd->poll_count++ < 12) {
+ sd->poll_source = g_timeout_add_seconds(2,
+ sim_state_check, cbd);
+ return;
+ }
+ }
+ /* fall through */
+ default:
cb(&error, -1, cbd->data);
- return;
+ goto done;
}
if (sd->vendor == OFONO_VENDOR_WAVECOM) {
@@ -887,7 +904,7 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer
user_data)
if (!g_at_result_iter_next(&iter, "+CPIN:")) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
- return;
+ goto done;
}
g_at_result_iter_next_unquoted_string(&iter, &pin_required);
@@ -903,12 +920,34 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer
user_data)
if (pin_type == OFONO_SIM_PASSWORD_INVALID) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
- return;
+ goto done;
}
DBG("crsm_pin_cb: %s", pin_required);
cb(&error, pin_type, cbd->data);
+
+done:
+ g_free(cbd);
+}
+
+static gboolean sim_state_check(gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct sim_data *sd = ofono_sim_get_data(cbd->user);
+ ofono_sim_passwd_cb_t cb = cbd->cb;
+
+ sd->poll_source = 0;
+
+ if (g_at_chat_send(sd->chat, "AT+CPIN?", cpin_prefix,
+ at_cpin_cb, cbd, NULL) > 0)
+ return FALSE;
+
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+
+ g_free(cbd);
+
+ return FALSE;
}
static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
@@ -919,13 +958,8 @@ static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t
cb,
cbd->user = sim;
- if (g_at_chat_send(sd->chat, "AT+CPIN?", cpin_prefix,
- at_cpin_cb, cbd, g_free) > 0)
- return;
-
- g_free(cbd);
-
- CALLBACK_WITH_FAILURE(cb, -1, data);
+ sd->poll_count = 0;
+ sim_state_check(cbd);
}
static void at_xsim_notify(GAtResult *result, gpointer user_data)
@@ -1246,6 +1280,9 @@ static void at_sim_remove(struct ofono_sim *sim)
{
struct sim_data *sd = ofono_sim_get_data(sim);
+ if (sd->poll_source > 0)
+ g_source_remove(sd->poll_source);
+
ofono_sim_set_data(sim, NULL);
g_at_chat_unref(sd->chat);
--
1.7.4.1