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

Call ofono_sim_ready_notify if pin code query returns SIM READY, unless
there is a vendor quirk for SIM status indications.

Schedule calls to ofono_sim_ready_notify() from vendor-specific
status indications:
- IFX: register unsolicated +XSIM result code
- MBM: register unsolicated *EPEV result code

IFX quirk also takes care of SIM presence notifications.
---
 drivers/atmodem/sim.c |  189 +++++++++++++++++++++++++++++++++++--------------
 1 files changed, 136 insertions(+), 53 deletions(-)

diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index d9c0d8d..88d9fc1 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 };
@@ -679,10 +683,49 @@ static void at_pin_retries_query(struct ofono_sim *sim,
        CALLBACK_WITH_FAILURE(cb, NULL, data);
 }
 
+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);
+
+       if (sd->ready_source > 0)
+               return;
+
+       sd->ready_source = g_timeout_add(READY_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;
@@ -732,6 +775,16 @@ static void at_cpin_cb(gboolean ok, GAtResult *result, 
gpointer user_data)
        DBG("crsm_pin_cb: %s", pin_required);
 
        cb(&error, pin_type, cbd->data);
+
+       if (pin_type != OFONO_SIM_PASSWORD_NONE)
+               return;
+
+       if (sd->ready_id > 0 && sd->ready == FALSE) {
+               at_wait_for_ready(sim);
+               return;
+       }
+
+       ofono_sim_ready_notify(sim);
 }
 
 static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
@@ -753,10 +806,8 @@ static void at_pin_query(struct ofono_sim *sim, 
ofono_sim_passwd_cb_t cb,
 
 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;
 
@@ -768,73 +819,69 @@ static void at_xsim_notify(GAtResult *result, gpointer 
user_data)
        if (!g_at_result_iter_next_number(&iter, &state))
                return;
 
+       DBG("state %d", state);
+
        switch (state) {
+       case 0: /* SIM not present */
+       case 9: /* SIM Removed */
+               ofono_sim_inserted_notify(sim, FALSE);
+               break;
+
+       case 1: /* PIN verification needed */
+       case 2: /* PIN verification not needed ??? Ready */
        case 3: /* PIN verified ??? Ready */
+       case 4: /* PUK verification needed */
+       case 5: /* SIM permanently blocked */
+               ofono_sim_inserted_notify(sim, TRUE);
+               /* Check for further lock codes */
+               ready_unregister_and_notify(sim);
+               break;
+
+       case 6: /* SIM Error */
+       case 8: /* SIM Technical Problem */
+               ofono_sim_inserted_notify(sim, TRUE);
+               break;
+
        case 7: /* ready for attach (+COPS) */
+               ofono_sim_inserted_notify(sim, TRUE);
+               sd->ready = TRUE;
+               ready_unregister_and_notify(sim);
                break;
+
        default:
-               return;
+               ofono_warn("Unknown SIM state %d received", state);
+               break;
        }
-
-       cb(&error, cbd->data);
-
-       g_at_chat_unregister(sd->chat, sd->ready_id);
-       sd->ready_id = 0;
 }
 
 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("");
+
+       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)
 {
        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,
@@ -845,12 +892,14 @@ static void at_pin_send(struct ofono_sim *sim, const char 
*passwd,
        char buf[64];
        int ret;
 
-       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));
 
@@ -871,12 +920,14 @@ static void at_pin_send_puk(struct ofono_sim *sim, const 
char *puk,
        char buf[64];
        int ret;
 
-       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));
 
@@ -1052,14 +1103,43 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned 
int vendor,
        case OFONO_VENDOR_WAVECOM:
                g_at_chat_add_terminator(sd->chat, "+CPIN:", 6, TRUE);
                break;
+
+       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);
+               /* Enable XSIM and XLOCK notifications */
+               g_at_chat_send(sd->chat, "AT+XSIMSTATE=1", none_prefix,
+                               NULL, NULL, NULL);
+               g_at_chat_send(sd->chat, "AT+XSIMSTATE?", none_prefix,
+                               NULL, NULL, NULL);
+               break;
+
        case OFONO_VENDOR_MBM:
-               g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
+               /*
+                * 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);
+               /* Enable *EPEV notifications */
+               g_at_chat_send(sd->chat, "AT*EPEE=1", none_prefix,
+                               NULL, NULL, NULL);
                break;
+
        default:
                break;
        }
 
        ofono_sim_set_data(sim, sd);
+
        g_idle_add(at_sim_register, sim);
 
        return 0;
@@ -1071,6 +1151,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