In this version watches are asssigned to simfs contexts so that
there's less free()ing for users to do.  This patch includes part of
EF cache flushing patch from the previous version.
---
 src/ofono.h |    4 +
 src/sim.c   |  226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/simfs.c |    5 ++
 src/simfs.h |    2 +
 4 files changed, 237 insertions(+), 0 deletions(-)

diff --git a/src/ofono.h b/src/ofono.h
index 6ba0187..b7fed13 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -299,6 +299,10 @@ ofono_bool_t __ofono_sim_service_available(struct 
ofono_sim *sim,
                                                int ust_service,
                                                int sst_service);
 
+void __ofono_sim_refresh(struct ofono_sim *sim, GSList *file_list,
+                               ofono_bool_t full_file_change,
+                               ofono_bool_t naa_init);
+
 #include <ofono/stk.h>
 
 typedef void (*__ofono_sms_sim_download_cb_t)(ofono_bool_t ok,
diff --git a/src/sim.c b/src/sim.c
index 52261c8..55d4d75 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -97,6 +97,7 @@ struct ofono_sim {
 
        struct sim_fs *simfs;
        struct ofono_sim_context *context;
+       GSList *fs_watches;
 
        unsigned char *iidf_image;
 
@@ -118,6 +119,14 @@ struct service_number {
        struct ofono_phone_number ph;
 };
 
+struct fs_watch {
+       int id;
+       enum ofono_sim_state reset_state;
+       ofono_sim_file_notify_t notify;
+       void *notify_data;
+       struct ofono_sim_context *context;
+};
+
 static const char *const passwd_name[] = {
        [OFONO_SIM_PASSWORD_NONE] = "none",
        [OFONO_SIM_PASSWORD_SIM_PIN] = "pin",
@@ -203,6 +212,51 @@ static enum ofono_sim_password_type puk2pin(enum 
ofono_sim_password_type type)
        }
 }
 
+static gint fs_watch_compare_by_id(gconstpointer a, gconstpointer b)
+{
+       const struct fs_watch *w = a;
+       const int *id = b;
+
+       return w->id - *id;
+}
+
+static gint fs_watch_compare_by_context(gconstpointer a, gconstpointer b)
+{
+       const struct fs_watch *w = a;
+
+       return (void *) w->context - b;
+}
+
+static int sim_add_file_watch(struct ofono_sim_context *context, int id,
+                               gboolean remove_atoms,
+                               ofono_sim_file_notify_t notify, void *userdata)
+{
+       struct ofono_sim *sim = sim_fs_context_get_sim(context);
+       struct fs_watch *item;
+
+       DBG("%p", sim);
+
+       if (sim == NULL)
+               return 0;
+
+       /* Currently there's no need for multiple watches per file */
+       if (g_slist_find_custom(sim->fs_watches, &id, fs_watch_compare_by_id))
+               return -EEXIST;
+
+       item = g_new0(struct fs_watch, 1);
+
+       item->id = id;
+       item->notify = notify;
+       item->notify_data = userdata;
+       item->reset_state = remove_atoms ? OFONO_SIM_STATE_INSERTED :
+               OFONO_SIM_STATE_READY;
+       item->context = context;
+
+       sim->fs_watches = g_slist_prepend(sim->fs_watches, item);
+
+       return id;
+}
+
 static char **get_own_numbers(GSList *own_numbers)
 {
        int nelem = 0;
@@ -1957,6 +2011,15 @@ struct ofono_sim_context 
*ofono_sim_context_create(struct ofono_sim *sim)
 
 void ofono_sim_context_free(struct ofono_sim_context *context)
 {
+       struct ofono_sim *sim = sim_fs_context_get_sim(context);
+       GSList *l;
+
+       while ((l = g_slist_find_custom(sim->fs_watches, context,
+                                       fs_watch_compare_by_context))) {
+               g_free(l->data);
+               sim->fs_watches = g_slist_remove(sim->fs_watches, l->data);
+       }
+
        return sim_fs_context_free(context);
 }
 
@@ -2278,6 +2341,12 @@ static void sim_remove(struct ofono_atom *atom)
        sim_fs_free(sim->simfs);
        sim->simfs = NULL;
 
+       if (sim->fs_watches != NULL) {
+               g_slist_foreach(sim->fs_watches, (GFunc) g_free, NULL);
+               g_slist_free(sim->fs_watches);
+               sim->fs_watches = NULL;
+       }
+
        g_free(sim);
 }
 
@@ -2364,3 +2433,160 @@ void *ofono_sim_get_data(struct ofono_sim *sim)
 {
        return sim->driver_data;
 }
+
+static void sim_file_changed_flush(struct ofono_sim *sim, int id)
+{
+       int i, imgid;
+
+       if (id == SIM_EFIMG_FILEID)
+               /* All cached images become invalid */
+               sim_fs_image_cache_flush(sim->simfs);
+       else if (sim->efimg) {
+               /*
+                * Data and CLUT for image instances stored in the changed
+                * file need to be re-read.
+                */
+               for (i = sim->efimg_length / 9 - 1; i >= 0; i--) {
+                       imgid = (sim->efimg[i * 9 + 3] << 8) |
+                               sim->efimg[i * 9 + 4];
+
+                       if (imgid == id)
+                               sim_fs_image_cache_flush_file(sim->simfs, i);
+               }
+       }
+
+       sim_fs_cache_flush_file(sim->simfs, id);
+}
+
+int ofono_sim_add_file_watch(struct ofono_sim_context *context, int id,
+                       ofono_sim_file_notify_t notify, void *userdata)
+{
+       return sim_add_file_watch(context, id, FALSE, notify, userdata);
+}
+
+void ofono_sim_remove_file_watch(struct ofono_sim_context *context, int id,
+                               ofono_sim_file_notify_t notify, void *userdata)
+{
+       struct ofono_sim *sim = sim_fs_context_get_sim(context);
+       GSList *item = g_slist_find_custom(sim->fs_watches,
+                                               &id, fs_watch_compare_by_id);
+
+       DBG("%p", sim);
+
+       if (!item)
+               return;
+
+       g_free(item->data);
+       sim->fs_watches = g_slist_remove(sim->fs_watches, item->data);
+}
+
+void __ofono_sim_refresh(struct ofono_sim *sim, GSList *file_list,
+                       ofono_bool_t full_file_change, ofono_bool_t naa_init)
+{
+       GSList *l, *fl;
+       enum sim_reset {
+               RESET_REMOVE_ATOMS      = OFONO_SIM_STATE_INSERTED,
+               RESET_SIGNAL_READY      = OFONO_SIM_STATE_READY,
+               RESET_NONE,
+       } reset_state = RESET_NONE;
+
+       /* Flush cached content for affected files */
+       if (full_file_change)
+               sim_fs_cache_flush(sim->simfs);
+       else {
+               for (fl = file_list; fl; fl = fl->next) {
+                       struct stk_file *file = fl->data;
+                       int id = (file->file[file->len - 2] << 8) |
+                               (file->file[file->len - 1] << 0);
+
+                       sim_file_changed_flush(sim, id);
+               }
+       }
+
+       if (naa_init)
+               reset_state = RESET_REMOVE_ATOMS;
+
+       /*
+        * Check if we have file change handlers for all of the affected
+        * files.  If not, we will fall back to re-initialising the
+        * application which ensures that all files are re-read.
+        */
+       for (l = sim->fs_watches; l; l = l->next) {
+               struct fs_watch *w = l->data;
+
+               if (full_file_change) {
+                       if (w->notify)
+                               continue;
+
+                       if (w->reset_state < reset_state)
+                               reset_state = reset_state;
+
+                       continue;
+               }
+
+               for (fl = file_list; fl; fl = fl->next) {
+                       struct stk_file *file = fl->data;
+                       int id = (file->file[file->len - 2] << 8) |
+                               (file->file[file->len - 1] << 0);
+
+                       if (id != w->id)
+                               continue;
+
+                       if (w->notify)
+                               break;
+
+                       if (w->reset_state < reset_state)
+                               reset_state = reset_state;
+
+                       break;
+               }
+       }
+
+       /*
+        * Notify the subscribers of files that have changed unless we
+        * have determined that a re-initialisation is necessary and
+        * will trigger re-reading of those files anyway.
+        */
+       for (l = sim->fs_watches; l; l = l->next) {
+               struct fs_watch *w = l->data;
+
+               if (full_file_change) {
+                       if (w->reset_state < reset_state)
+                               w->notify(w->id, w->notify_data);
+
+                       continue;
+               }
+
+               for (fl = file_list; fl; fl = fl->next) {
+                       struct stk_file *file = fl->data;
+                       int id = (file->file[file->len - 2] << 8) |
+                               (file->file[file->len - 1] << 0);
+
+                       if (id != w->id)
+                               continue;
+
+                       if (w->reset_state < reset_state)
+                               w->notify(w->id, w->notify_data);
+
+                       break;
+               }
+       }
+
+       switch (reset_state) {
+       case RESET_REMOVE_ATOMS:
+               /*
+                * REVISIT: There's some concern that on re-insertion the
+                * atoms will start to talk to the SIM before it becomes
+                * ready, on certain SIMs.
+                */
+               ofono_sim_inserted_notify(sim, FALSE);
+               ofono_sim_inserted_notify(sim, TRUE);
+               break;
+       case RESET_SIGNAL_READY:
+               sim->state = OFONO_SIM_STATE_INSERTED;
+               sim_set_ready(sim);
+               break;
+       case RESET_NONE:
+               break;
+       }
+}
diff --git a/src/simfs.c b/src/simfs.c
index 0459447..f829161 100644
--- a/src/simfs.c
+++ b/src/simfs.c
@@ -167,6 +167,11 @@ void sim_fs_context_free(struct ofono_sim_context *context)
        g_free(context);
 }
 
+struct ofono_sim *sim_fs_context_get_sim(struct ofono_sim_context *context)
+{
+       return context->fs->sim;
+}
+
 static void sim_fs_end_current(struct sim_fs *fs)
 {
        struct sim_fs_op *op = g_queue_pop_head(fs->op_q);
diff --git a/src/simfs.h b/src/simfs.h
index d93d96e..5623175 100644
--- a/src/simfs.h
+++ b/src/simfs.h
@@ -56,3 +56,5 @@ void sim_fs_image_cache_flush_file(struct sim_fs *fs, int id);
 
 void sim_fs_free(struct sim_fs *fs);
 void sim_fs_context_free(struct ofono_sim_context *context);
+
+struct ofono_sim *sim_fs_context_get_sim(struct ofono_sim_context *context);
-- 
1.7.1.86.g0e460.dirty

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to