From: Pekka Pessi <pekka.pe...@nokia.com>

Schedule a call to ofono_sim_ready_notify after pin code query returns
SIM READY.

Vendor quirks:
- IFX: register unsolicated +XSIM result code
- MBM: register unsolicated *EPEV result code
---
 drivers/atmodem/sim.c |  166 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 117 insertions(+), 49 deletions(-)

diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index b1d971d..44d9047 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -46,10 +46,14 @@
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
+#define READY_TIMEOUT          5000
+
 struct sim_data {
        GAtChat *chat;
        unsigned int vendor;
        guint ready_id;
+       guint ready_source;
+       ofono_bool_t ready;
 };
 
 static const char *crsm_prefix[] = { "+CRSM:", NULL };
@@ -558,10 +562,55 @@ static void at_pin_retries_query(struct ofono_sim *sim,
        }
 }
 
+static void ready_unregister_and_notify(struct ofono_sim *sim)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+
+       DBG("");
+
+       if (sd->ready_source > 0) {
+               g_source_remove(sd->ready_source);
+               sd->ready_source = 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("");
+
+       sd->ready_source = 0;
+
+       ofono_sim_ready_notify(sim);
+
+       return FALSE;
+}
+
+static void at_wait_for_ready(struct ofono_sim *sim)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+       guint timeout;
+
+       if (sd->ready_source > 0)
+               return;
+
+       if (!sd->ready && sd->ready_id > 0)
+               timeout = READY_TIMEOUT;
+       else
+               timeout = 0;
+
+       sd->ready_source = g_timeout_add(timeout, ready_timeout, sim);
+}
+
 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;
@@ -608,6 +657,11 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, 
gpointer user_data)
                return;
        }
 
+       if (pin_type == OFONO_SIM_PASSWORD_NONE)
+               at_wait_for_ready(sim);
+       else
+               sd->ready = FALSE;
+
        DBG("crsm_pin_cb: %s", pin_required);
 
        cb(&error, pin_type, cbd->data);
@@ -636,13 +690,13 @@ 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;
 
+       DBG("");
+
        g_at_result_iter_init(&iter, result);
 
        if (!g_at_result_iter_next(&iter, "+XSIM:"))
@@ -659,65 +713,40 @@ 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);
+       DBG("");
 
-       g_at_chat_unregister(sd->chat, sd->ready_id);
-       sd->ready_id = 0;
+       sd->ready = TRUE;
+
+       if (sd->ready_source > 0)
+               ready_unregister_and_notify(sim);
 }
 
 static void at_pin_send_cb(gboolean ok, GAtResult *result,
                                gpointer user_data)
 {
        struct cb_data *cbd = user_data;
-       struct sim_data *sd = cbd->user;
+       struct ofono_sim *sim = cbd->user;
+       struct sim_data *sd = ofono_sim_get_data(sim);
        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 && sd->ready_id)
+               at_wait_for_ready(sim);
 
-       if (!ok)
-               goto done;
-
-       switch (sd->vendor) {
-       case OFONO_VENDOR_IFX:
-               /*
-                * On the IFX modem, AT+CPIN? can return READY too
-                * early and so use +XSIM notification to detect
-                * the ready state of the SIM.
-                */
-               sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
-                                                       at_xsim_notify,
-                                                       FALSE, cbd, g_free);
-               return;
-       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.
-                */
-               sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
-                                                       at_epev_notify,
-                                                       FALSE, cbd, g_free);
-               return;
-       }
+       decode_at_error(&error, g_at_result_final_response(result));
 
-done:
        cb(&error, cbd->data);
-
-       g_free(cbd);
 }
 
 static void at_pin_send(struct ofono_sim *sim, const char *passwd,
@@ -731,12 +760,14 @@ static void at_pin_send(struct ofono_sim *sim, const char 
*passwd,
        if (cbd == NULL)
                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));
 
@@ -761,12 +792,14 @@ static void at_pin_send_puk(struct ofono_sim *sim, const 
char *puk,
        if (cbd == NULL)
                goto error;
 
-       cbd->user = sd;
+       cbd->user = sim;
+
+       sd->ready = FALSE;
 
        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));
 
@@ -938,6 +971,35 @@ static gboolean at_sim_register(gpointer user)
        return FALSE;
 }
 
+static void at_register_ready(struct ofono_sim *sim)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+
+       switch (sd->vendor) {
+       case OFONO_VENDOR_IFX:
+               /*
+                * On the IFX modem, AT+CPIN? can return READY too
+                * early and so use +XSIM notification to detect
+                * the ready state of the SIM.
+                */
+               sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
+                                                       at_xsim_notify,
+                                                       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.
+                */
+               sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
+                                                       at_epev_notify,
+                                                       FALSE, sim, NULL);
+               break;
+       }
+}
+
 static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
                                void *data)
 {
@@ -960,6 +1022,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;
@@ -971,6 +1036,9 @@ static void at_sim_remove(struct ofono_sim *sim)
 
        ofono_sim_set_data(sim, NULL);
 
+       if (sd->ready_source > 0)
+               g_source_remove(sd->ready_source);
+
        g_at_chat_unref(sd->chat);
        g_free(sd);
 }
-- 
1.7.1

_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to