From: Pekka Pessi <Pekka.Pessi(a)nokia.com>
Retry with ofono_sim_ready_notify after a timeout if CPIN? returns CME
error 14 (SIM busy).
If there is a ready notification registered but no such notification has
been received, return the CME error 14. If ready notification has been
received, return normally.
---
drivers/atmodem/sim.c | 182 +++++++++++++++++++++++++++++++++++++++----------
src/simutil.h | 2 +
2 files changed, 147 insertions(+), 37 deletions(-)
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index 9cfdc65..3ea8f87 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -44,10 +44,17 @@
#define EF_STATUS_INVALIDATED 0
#define EF_STATUS_VALID 1
+/* Timeout in milliseconds when there is ready notification */
+#define READY_TIMEOUT 5000
+/* Timeout in milliseconds without ready notification */
+#define BUSY_TIMEOUT 500
+
struct sim_data {
GAtChat *chat;
unsigned int vendor;
+ ofono_bool_t ready;
guint ready_id;
+ guint ready_source;
};
static const char *crsm_prefix[] = { "+CRSM:", NULL };
@@ -456,10 +463,65 @@ static struct {
{ OFONO_SIM_PASSWORD_PHCORP_PUK, "PH-CORP PUK" },
};
+static void ready_unregister_and_notify(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ DBG("enter");
+
+ if (sd->ready_source > 0)
+ g_source_remove(sd->ready_source);
+ sd->ready_source = 0;
+
+ if (sd->ready_id > 0)
+ g_at_chat_unregister(sd->chat, sd->ready_id);
+ sd->ready_id = 0;
+
+ ofono_sim_ready_notify(sim);
+}
+
+static gboolean ready_timeout(gpointer user_data)
+{
+ struct ofono_sim *sim = user_data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ DBG("enter");
+
+ sd->ready_source = 0;
+ ready_unregister_and_notify(sim);
+
+ return FALSE;
+}
+
+static void at_check_sim_busy(struct ofono_sim *sim,
+ struct ofono_error *error)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ if (error->type != OFONO_ERROR_TYPE_CME)
+ return;
+ if (error->error != 14)
+ return;
+
+ if (sd->ready_source > 0)
+ return;
+
+ sd->ready_source = g_timeout_add(BUSY_TIMEOUT, ready_timeout, sim);
+}
+
+#define CALLBACK_WITH_SIM_BUSY(f, args...) \
+ do { \
+ struct ofono_error e; \
+ e.type = OFONO_ERROR_TYPE_CME; \
+ e.error = 14; \
+ f(&e, ##args); \
+ } while (0)
+
static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
- struct sim_data *sd = ofono_sim_get_data(cbd->user);
+ struct ofono_sim *sim = cbd->user;
+ struct sim_data *sd = ofono_sim_get_data(sim);
GAtResultIter iter;
ofono_sim_passwd_cb_t cb = cbd->cb;
struct ofono_error error;
@@ -475,6 +537,7 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer
user_data)
decode_at_error(&error, final);
if (!ok) {
+ at_check_sim_busy(sim, &error);
cb(&error, -1, cbd->data);
return;
}
@@ -506,8 +569,18 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer
user_data)
return;
}
- DBG("crsm_pin_cb: %s", pin_required);
+ if (!sd->ready && sd->ready_id > 0 && sd->ready_source >
0) {
+ CALLBACK_WITH_SIM_BUSY(cb, -1, cbd->data);
+ return;
+ }
+ switch (pin_type) {
+ case OFONO_SIM_PASSWORD_SIM_PIN:
+ case OFONO_SIM_PASSWORD_SIM_PUK:
+ sd->ready = FALSE;
+ }
+
+ DBG("crsm_pin_cb: %s", pin_required);
cb(&error, pin_type, cbd->data);
}
@@ -534,10 +607,8 @@ error:
static void at_xsim_notify(GAtResult *result, gpointer user_data)
{
- struct cb_data *cbd = user_data;
- struct sim_data *sd = cbd->user;
- ofono_sim_lock_unlock_cb_t cb = cbd->cb;
- struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
+ struct ofono_sim *sim = user_data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
GAtResultIter iter;
int state;
@@ -557,37 +628,29 @@ static void at_xsim_notify(GAtResult *result, gpointer user_data)
return;
}
- cb(&error, cbd->data);
+ sd->ready = TRUE;
- g_at_chat_unregister(sd->chat, sd->ready_id);
- sd->ready_id = 0;
+ if (sd->ready_source > 0)
+ ready_unregister_and_notify(sim);
}
static void at_epev_notify(GAtResult *result, gpointer user_data)
{
- struct cb_data *cbd = user_data;
- struct sim_data *sd = cbd->user;
- ofono_sim_lock_unlock_cb_t cb = cbd->cb;
- struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
+ struct ofono_sim *sim = user_data;
+ struct sim_data *sd = ofono_sim_get_data(sim);
- cb(&error, cbd->data);
+ sd->ready = TRUE;
- g_at_chat_unregister(sd->chat, sd->ready_id);
- sd->ready_id = 0;
+ if (sd->ready_source > 0)
+ ready_unregister_and_notify(sim);
}
-static void at_pin_send_cb(gboolean ok, GAtResult *result,
- gpointer user_data)
+static void at_register_ready(struct ofono_sim *sim)
{
- struct cb_data *cbd = user_data;
- struct sim_data *sd = cbd->user;
- ofono_sim_lock_unlock_cb_t cb = cbd->cb;
- struct ofono_error error;
-
- decode_at_error(&error, g_at_result_final_response(result));
+ struct sim_data *sd = ofono_sim_get_data(sim);
- if (!ok)
- goto done;
+ if (sd->ready_id > 0)
+ return;
switch (sd->vendor) {
case OFONO_VENDOR_IFX:
@@ -598,24 +661,64 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
*/
sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
at_xsim_notify,
- FALSE, cbd, g_free);
- return;
+ FALSE, sim, NULL);
+ break;
+
case OFONO_VENDOR_MBM:
/*
* On the MBM modem, AT+CPIN? keeps returning SIM PIN
* for a moment after successful AT+CPIN="..", but then
- * sends *EPEV when that changes.
+ * sends *EPEV when that changes. Sometimes.
*/
sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
at_epev_notify,
- FALSE, cbd, g_free);
+ FALSE, sim, NULL);
+ break;
+ }
+}
+
+static void at_wait_for_ready(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ guint timeout;
+
+ if (sd->ready)
+ return;
+
+ at_register_ready(sim);
+
+ switch (sd->vendor) {
+ case OFONO_VENDOR_IFX:
+ timeout = READY_TIMEOUT;
+ break;
+
+ case OFONO_VENDOR_MBM:
+ timeout = READY_TIMEOUT;
+ break;
+
+ default:
return;
}
-done:
- cb(&error, cbd->data);
+ if (sd->ready_source)
+ g_source_remove(sd->ready_source);
+ sd->ready_source = g_timeout_add(timeout, ready_timeout, sim);
+}
- g_free(cbd);
+static void at_pin_send_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_sim *sim = cbd->user;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (ok)
+ at_wait_for_ready(sim);
+
+ cb(&error, cbd->data);
}
static void at_pin_send(struct ofono_sim *sim, const char *passwd,
@@ -629,12 +732,14 @@ static void at_pin_send(struct ofono_sim *sim, const char *passwd,
if (!cbd)
goto error;
- cbd->user = sd;
+ cbd->user = sim;
+
+ sd->ready = FALSE;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
ret = g_at_chat_send(sd->chat, buf, none_prefix,
- at_pin_send_cb, cbd, NULL);
+ at_pin_send_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
@@ -659,12 +764,12 @@ static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
if (!cbd)
goto error;
- cbd->user = sd;
+ cbd->user = sim;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk,
passwd);
ret = g_at_chat_send(sd->chat, buf, none_prefix,
- at_pin_send_cb, cbd, NULL);
+ at_pin_send_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
@@ -858,6 +963,9 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
}
ofono_sim_set_data(sim, sd);
+
+ at_register_ready(sim);
+
g_idle_add(at_sim_register, sim);
return 0;
diff --git a/src/simutil.h b/src/simutil.h
index 5b56099..7b07f16 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -24,6 +24,7 @@ enum sim_fileid {
SIM_EF_ICCID_FILEID = 0x2fe2,
SIM_EFIMG_FILEID = 0x4F20,
SIM_EFLI_FILEID = 0x6f05,
+ SIM_EFIMSI_FILEID = 0x6f07,
SIM_EF_CPHS_MWIS_FILEID = 0x6f11,
SIM_EF_CPHS_INFORMATION_FILEID = 0x6f16,
SIM_EF_CPHS_MBDN_FILEID = 0x6f17,
@@ -45,6 +46,7 @@ enum sim_fileid {
SIM_EFSPDI_FILEID = 0x6fcd,
SIM_EFECC_FILEID = 0x6fb7,
SIM_EFCBMIR_FILEID = 0x6f50,
+ SIM_EFNIA_FILEID = 0x6f51,
SIM_EFCBMI_FILEID = 0x6f45,
SIM_EFCBMID_FILEID = 0x6f48,
};
--
1.7.1