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