Hi Pekka,

On 02/08/2011 06:32 AM, pekka.pe...@nokia.com wrote:
> 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 d9c0d8d..666edbe 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,55 @@ 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);
> +     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;
> @@ -729,6 +778,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;
> +

So all this logic seems to work by luck.  oFono roughly does this:
pin_query:
send AT+CPIN?
if READY then set waiting_for_pin to none, and wait in
ofono_sim_ready_notify
if PIN then set waiting_for_pin to the pin, and wait in
ofono_sim_ready_notify

ofono_sim_ready_notify:
if waiting_for_pin is none proceed with initialization
otherwise go back to pin_query

Here's a log of this running on IFX:
ofonod[521]: Aux: > AT+CPIN?\r
ofonod[521]: Aux: < \r\n+CPIN: SIM PIN\r\n
ofonod[521]: Aux: < \r\nOK\r\n
ofonod[521]: drivers/atmodem/sim.c:at_cpin_cb() crsm_pin_cb: SIM PIN
....
ofonod[521]: Aux: > AT+CPIN="0000"\r
ofonod[521]: Aux: < \r\nOK\r\n
ofonod[521]: Aux: > AT+CPIN?\r
ofonod[521]: Aux: < \r\n+CME ERROR: 14\r\n
ofonod[521]: Querying PIN authentication state failed
....
ofonod[521]: Aux: < \r\n+XSIM: 7\r\n
ofonod[521]: drivers/atmodem/sim.c:at_xsim_notify()
ofonod[521]: drivers/atmodem/sim.c:ready_unregister_and_notify()
ofonod[521]: src/sim.c:ofono_sim_ready_notify()
ofonod[521]: plugins/ifx.c:xsim_notify() state 7
ofonod[521]: Aux: > AT+CPIN?\r
ofonod[521]: Aux: < \r\n+CPIN: READY\r\n
ofonod[521]: Aux: < \r\nOK\r\n
ofonod[521]: drivers/atmodem/sim.c:at_cpin_cb() crsm_pin_cb: READY
ofonod[521]: drivers/atmodem/sim.c:at_pin_retries_query()
ofonod[521]: drivers/atmodem/sim.c:ready_timeout()
ofonod[521]: src/sim.c:ofono_sim_ready_notify()

As you can see, we are in fact calling ofono_sim_ready_notify twice in
short succession.  The only reason we're not stuck for 5 seconds the
second time around is that the xsim notification function sets ready to
TRUE.  This is all pretty convoluted.  I don't really like this at all.

Another case to consider is a cold boot quirked modem, PIN disabled.  We
are highly likely to receive XSIM way before we even query the PIN.  So
ready is false, ready_id is > 0 and we end up waiting for 5 seconds here
for no good reason.

>       DBG("crsm_pin_cb: %s", pin_required);
>  
>       cb(&error, pin_type, cbd->data);
> @@ -753,13 +807,13 @@ 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;
>  
> +     DBG("");
> +
>       g_at_result_iter_init(&iter, result);
>  
>       if (!g_at_result_iter_next(&iter, "+XSIM:"))
> @@ -776,65 +830,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);

Did you intend if (ok && sd_ready_id == 0) here?

Otherwise I don't see how non-quirked modems ever signal sim_ready or
why you would want to start a timer if you know a notification is coming
anyway.

>  
> -     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 +874,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 +902,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));
>  
> @@ -1038,6 +1071,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)
>  {
> @@ -1060,6 +1122,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;
> @@ -1071,6 +1136,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);
>  }

Regards,
-Denis
_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to