diff options
-rw-r--r-- | drivers/atmodem/sim.c | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c index 21bc933f..987dd7c1 100644 --- a/drivers/atmodem/sim.c +++ b/drivers/atmodem/sim.c @@ -44,8 +44,8 @@ struct sim_data { GAtChat *chat; unsigned int vendor; - guint epev_id; - guint epev_source; + guint ready_id; + guint ready_source; }; static const char *crsm_prefix[] = { "+CRSM:", NULL }; @@ -522,18 +522,47 @@ error: CALLBACK_WITH_FAILURE(cb, -1, data); } -static gboolean at_epev_unregister(gpointer user_data) +static gboolean ready_notify_unregister(gpointer user_data) { struct sim_data *sd = user_data; - sd->epev_source = 0; + sd->ready_source = 0; - g_at_chat_unregister(sd->chat, sd->epev_id); - sd->epev_id = 0; + g_at_chat_unregister(sd->chat, sd->ready_id); + sd->ready_id = 0; return FALSE; } +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 }; + GAtResultIter iter; + int state; + + if (sd->ready_source > 0) + return; + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+XSIM:")) + return; + + if (!g_at_result_iter_next_number(&iter, &state)) + return; + + /* check for state 3 (PIN verified – Ready) */ + if (state != 3) + return; + + cb(&error, cbd->data); + + sd->ready_source = g_timeout_add(0, ready_notify_unregister, sd); +} + static void at_epev_notify(GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; @@ -541,12 +570,12 @@ static void at_epev_notify(GAtResult *result, gpointer user_data) ofono_sim_lock_unlock_cb_t cb = cbd->cb; struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR }; - if (sd->epev_source) + if (sd->ready_source > 0) return; cb(&error, cbd->data); - sd->epev_source = g_timeout_add(0, at_epev_unregister, sd); + sd->ready_source = g_timeout_add(0, ready_notify_unregister, sd); } static void at_pin_send_cb(gboolean ok, GAtResult *result, @@ -559,17 +588,33 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result, decode_at_error(&error, g_at_result_final_response(result)); - /* - * On the MBM modem, AT+CPIN? keeps returning SIM PIN for a moment - * after successful AT+CPIN="..", but sends *EPEV when that changes. - */ - if (ok && sd->vendor == OFONO_VENDOR_MBM) { - sd->epev_id = g_at_chat_register(sd->chat, "*EPEV", + 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; } +done: cb(&error, cbd->data); g_free(cbd); @@ -824,8 +869,8 @@ static void at_sim_remove(struct ofono_sim *sim) ofono_sim_set_data(sim, NULL); - if (sd->epev_source) - g_source_remove(sd->epev_source); + if (sd->ready_source > 0) + g_source_remove(sd->ready_source); g_at_chat_unref(sd->chat); g_free(sd); |