summaryrefslogtreecommitdiffstats
path: root/src/sim.c
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2009-08-18 17:05:03 -0500
committerDenis Kenzior <denkenz@gmail.com>2009-08-19 18:35:06 -0500
commit5e7240512044b2826789084ad4d8a0165149be71 (patch)
tree1e4ab29ed36a899187af2fc0ef7bd782eb9b6de5 /src/sim.c
parent3b043e9b1a08d2a17defe875fb408079095aebd0 (diff)
downloadofono-5e7240512044b2826789084ad4d8a0165149be71.tar.bz2
Evolve SIM driver
Diffstat (limited to 'src/sim.c')
-rw-r--r--src/sim.c530
1 files changed, 314 insertions, 216 deletions
diff --git a/src/sim.c b/src/sim.c
index 49422e4f..8171d630 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -37,11 +37,9 @@
#include "ofono.h"
-#include "driver.h"
#include "common.h"
#include "util.h"
#include "smsutil.h"
-#include "sim.h"
#include "simutil.h"
#ifdef TEMP_FAILURE_RETRY
@@ -57,9 +55,11 @@
#define SIM_CACHE_PATH_LEN(imsilen) (strlen(SIM_CACHE_PATH) - 2 + imsilen)
#define SIM_CACHE_HEADER_SIZE 6
+static GSList *g_drivers = NULL;
+
static gboolean sim_op_next(gpointer user_data);
static gboolean sim_op_retrieve_next(gpointer user);
-static void sim_own_numbers_update(struct ofono_modem *modem);
+static void sim_own_numbers_update(struct ofono_sim *sim);
struct sim_file_op {
int id;
@@ -74,27 +74,36 @@ struct sim_file_op {
void *userdata;
};
-struct sim_manager_data {
- struct ofono_sim_ops *ops;
+struct ofono_sim {
char *imsi;
GSList *own_numbers;
GSList *new_numbers;
- GSList *ready_notify;
gboolean ready;
GQueue *simop_q;
gint simop_source;
-
unsigned char efmsisdn_length;
unsigned char efmsisdn_records;
+ unsigned int next_ready_watch_id;
+ GSList *ready_watches;
+ const struct ofono_sim_driver *driver;
+ void *driver_data;
+ struct ofono_atom *atom;
};
struct msisdn_set_request {
- struct ofono_modem *modem;
+ struct ofono_sim *sim;
int pending;
int failed;
DBusMessage *msg;
};
+struct sim_ready_watch {
+ unsigned int id;
+ ofono_sim_ready_notify_cb_t notify;
+ void *data;
+ ofono_destroy_func destroy;
+};
+
static char **get_own_numbers(GSList *own_numbers)
{
int nelem = 0;
@@ -122,44 +131,10 @@ static void sim_file_op_free(struct sim_file_op *node)
g_free(node);
}
-static struct sim_manager_data *sim_manager_create()
-{
- return g_try_new0(struct sim_manager_data, 1);
-}
-
-static void sim_manager_destroy(gpointer userdata)
-{
- struct ofono_modem *modem = userdata;
- struct sim_manager_data *data = modem->sim_manager;
-
- if (data->imsi) {
- g_free(data->imsi);
- data->imsi = NULL;
- }
-
- if (data->own_numbers) {
- g_slist_foreach(data->own_numbers, (GFunc)g_free, NULL);
- g_slist_free(data->own_numbers);
- data->own_numbers = NULL;
- }
-
- if (data->simop_source) {
- g_source_remove(data->simop_source);
- data->simop_source = 0;
- }
-
- if (data->simop_q) {
- g_queue_foreach(data->simop_q, (GFunc)sim_file_op_free, NULL);
- g_queue_free(data->simop_q);
- data->simop_q = NULL;
- }
-}
-
static DBusMessage *sim_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- struct ofono_modem *modem = data;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = data;
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter dict;
@@ -202,12 +177,12 @@ static void msisdn_set_done(struct msisdn_set_request *req)
__ofono_dbus_pending_reply(&req->msg, reply);
/* Re-read the numbers and emit signal if needed */
- sim_own_numbers_update(req->modem);
+ sim_own_numbers_update(req->sim);
g_free(req);
}
-static void msisdn_set_cb(struct ofono_modem *modem, int ok, void *data)
+static void msisdn_set_cb(int ok, void *data)
{
struct msisdn_set_request *req = data;
@@ -220,10 +195,9 @@ static void msisdn_set_cb(struct ofono_modem *modem, int ok, void *data)
msisdn_set_done(req);
}
-static gboolean set_own_numbers(struct ofono_modem *modem,
+static gboolean set_own_numbers(struct ofono_sim *sim,
GSList *new_numbers, DBusMessage *msg)
{
- struct sim_manager_data *sim = modem->sim_manager;
struct msisdn_set_request *req;
int record;
unsigned char efmsisdn[255];
@@ -234,7 +208,7 @@ static gboolean set_own_numbers(struct ofono_modem *modem,
req = g_new0(struct msisdn_set_request, 1);
- req->modem = modem;
+ req->sim = sim;
req->msg = dbus_message_ref(msg);
for (record = 1; record <= sim->efmsisdn_records; record++) {
@@ -245,7 +219,7 @@ static gboolean set_own_numbers(struct ofono_modem *modem,
} else
memset(efmsisdn, 0xff, sim->efmsisdn_length);
- if (ofono_sim_write(req->modem, SIM_EFMSISDN_FILEID,
+ if (ofono_sim_write(req->sim, SIM_EFMSISDN_FILEID,
msisdn_set_cb, OFONO_SIM_FILE_STRUCTURE_FIXED,
record, efmsisdn,
sim->efmsisdn_length, req) == 0)
@@ -263,8 +237,7 @@ static gboolean set_own_numbers(struct ofono_modem *modem,
static DBusMessage *sim_set_property(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct ofono_modem *modem = data;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = data;
DBusMessageIter iter;
DBusMessageIter var;
DBusMessageIter var_elem;
@@ -321,7 +294,7 @@ static DBusMessage *sim_set_property(DBusConnection *conn, DBusMessage *msg,
}
own_numbers = g_slist_reverse(own_numbers);
- set_ok = set_own_numbers(modem, own_numbers, msg);
+ set_ok = set_own_numbers(sim, own_numbers, msg);
error:
g_slist_foreach(own_numbers, (GFunc) g_free, 0);
@@ -334,14 +307,14 @@ error:
return __ofono_error_invalid_args(msg);
}
-static GDBusMethodTable sim_manager_methods[] = {
+static GDBusMethodTable sim_methods[] = {
{ "GetProperties", "", "a{sv}", sim_get_properties },
{ "SetProperty", "sv", "", sim_set_property,
G_DBUS_METHOD_FLAG_ASYNC },
{ }
};
-static GDBusSignalTable sim_manager_signals[] = {
+static GDBusSignalTable sim_signals[] = {
{ "PropertyChanged", "sv" },
{ }
};
@@ -368,13 +341,13 @@ static gboolean numbers_list_equal(GSList *a, GSList *b)
return TRUE;
}
-static void sim_msisdn_read_cb(struct ofono_modem *modem, int ok,
+static void sim_msisdn_read_cb(int ok,
enum ofono_sim_file_structure structure,
int length, int record,
const unsigned char *data,
int record_length, void *userdata)
{
- struct sim_manager_data *sim = userdata;
+ struct ofono_sim *sim = userdata;
int total;
struct ofono_phone_number ph;
@@ -409,6 +382,7 @@ check:
sim->new_numbers = g_slist_reverse(sim->new_numbers);
if (!numbers_list_equal(sim->new_numbers, sim->own_numbers)) {
+ const char *path = __ofono_atom_get_path(sim->atom);
char **own_numbers;
DBusConnection *conn = ofono_dbus_get_connection();
@@ -418,7 +392,7 @@ check:
own_numbers = get_own_numbers(sim->own_numbers);
- ofono_dbus_signal_array_property_changed(conn, modem->path,
+ ofono_dbus_signal_array_property_changed(conn, path,
SIM_MANAGER_INTERFACE,
"SubscriberNumbers",
DBUS_TYPE_STRING,
@@ -432,22 +406,23 @@ check:
sim->new_numbers = NULL;
}
-static void sim_own_numbers_update(struct ofono_modem *modem)
+static void sim_own_numbers_update(struct ofono_sim *sim)
{
- ofono_sim_read(modem, SIM_EFMSISDN_FILEID,
- sim_msisdn_read_cb, modem->sim_manager);
+ ofono_sim_read(sim, SIM_EFMSISDN_FILEID,
+ sim_msisdn_read_cb, sim);
}
-static void sim_ready(struct ofono_modem *modem)
+static void sim_ready(void *user)
{
- sim_own_numbers_update(modem);
+ struct ofono_sim *sim = user;
+
+ sim_own_numbers_update(sim);
}
static void sim_imsi_cb(const struct ofono_error *error, const char *imsi,
void *data)
{
- struct ofono_modem *modem = data;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
ofono_error("Unable to read IMSI, emergency calls only");
@@ -456,20 +431,18 @@ static void sim_imsi_cb(const struct ofono_error *error, const char *imsi,
sim->imsi = g_strdup(imsi);
- ofono_sim_set_ready(modem);
+ ofono_sim_set_ready(sim);
}
-static void sim_retrieve_imsi(struct ofono_modem *modem)
+static void sim_retrieve_imsi(struct ofono_sim *sim)
{
- struct sim_manager_data *sim = modem->sim_manager;
-
- if (!sim->ops->read_imsi) {
+ if (!sim->driver->read_imsi) {
ofono_error("IMSI retrieval not implemented,"
" only emergency calls will be available");
return;
}
- sim->ops->read_imsi(modem, sim_imsi_cb, modem);
+ sim->driver->read_imsi(sim, sim_imsi_cb, sim);
}
static int create_dirs(const char *filename, const mode_t mode)
@@ -500,20 +473,19 @@ static int create_dirs(const char *filename, const mode_t mode)
return 0;
}
-static void sim_op_error(struct ofono_modem *modem)
+static void sim_op_error(struct ofono_sim *sim)
{
- struct sim_manager_data *sim = modem->sim_manager;
struct sim_file_op *op = g_queue_pop_head(sim->simop_q);
if (g_queue_get_length(sim->simop_q) > 0)
- sim->simop_source = g_timeout_add(0, sim_op_next, modem);
+ sim->simop_source = g_timeout_add(0, sim_op_next, sim);
if (op->is_read == TRUE)
((ofono_sim_file_read_cb_t) op->cb)
- (modem, 0, 0, 0, 0, 0, 0, op->userdata);
+ (0, 0, 0, 0, 0, 0, op->userdata);
else
((ofono_sim_file_write_cb_t) op->cb)
- (modem, 0, op->userdata);
+ (0, op->userdata);
sim_file_op_free(op);
}
@@ -546,19 +518,18 @@ static gboolean cache_record(const char *path, int current, int record_len,
static void sim_op_retrieve_cb(const struct ofono_error *error,
const unsigned char *data, int len, void *user)
{
- struct ofono_modem *modem = user;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = user;
struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
int total = op->length / op->record_length;
ofono_sim_file_read_cb_t cb = op->cb;
char *imsi = sim->imsi;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- sim_op_error(modem);
+ sim_op_error(sim);
return;
}
- cb(modem, 1, op->structure, op->length, op->current,
+ cb(1, op->structure, op->length, op->current,
data, op->record_length, op->userdata);
if (op->cache && imsi) {
@@ -575,52 +546,49 @@ static void sim_op_retrieve_cb(const struct ofono_error *error,
sim_file_op_free(op);
if (g_queue_get_length(sim->simop_q) > 0)
- sim->simop_source = g_timeout_add(0, sim_op_next,
- modem);
+ sim->simop_source = g_timeout_add(0, sim_op_next, sim);
} else {
op->current += 1;
- sim->simop_source = g_timeout_add(0, sim_op_retrieve_next,
- modem);
+ sim->simop_source = g_timeout_add(0, sim_op_retrieve_next, sim);
}
}
static gboolean sim_op_retrieve_next(gpointer user)
{
- struct ofono_modem *modem = user;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = user;
struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
sim->simop_source = 0;
switch (op->structure) {
case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
- if (!sim->ops->read_file_transparent) {
- sim_op_error(modem);
+ if (!sim->driver->read_file_transparent) {
+ sim_op_error(sim);
return FALSE;
}
- sim->ops->read_file_transparent(modem, op->id, 0, op->length,
- sim_op_retrieve_cb, modem);
+ sim->driver->read_file_transparent(sim, op->id, 0, op->length,
+ sim_op_retrieve_cb, sim);
break;
case OFONO_SIM_FILE_STRUCTURE_FIXED:
- if (!sim->ops->read_file_linear) {
- sim_op_error(modem);
+ if (!sim->driver->read_file_linear) {
+ sim_op_error(sim);
return FALSE;
}
- sim->ops->read_file_linear(modem, op->id, op->current,
+ sim->driver->read_file_linear(sim, op->id, op->current,
op->record_length,
- sim_op_retrieve_cb, modem);
+ sim_op_retrieve_cb, sim);
break;
case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
- if (!sim->ops->read_file_cyclic) {
- sim_op_error(modem);
+ if (!sim->driver->read_file_cyclic) {
+ sim_op_error(sim);
return FALSE;
}
- sim->ops->read_file_cyclic(modem, op->id, op->current,
+ sim->driver->read_file_cyclic(sim, op->id, op->current,
op->record_length,
- sim_op_retrieve_cb, modem);
+ sim_op_retrieve_cb, sim);
break;
default:
ofono_error("Unrecognized file structure, this can't happen");
@@ -661,8 +629,7 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
int record_length,
const unsigned char access[3], void *data)
{
- struct ofono_modem *modem = data;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = data;
struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
char *imsi = sim->imsi;
enum sim_file_access update;
@@ -670,7 +637,7 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
enum sim_file_access rehabilitate;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- sim_op_error(modem);
+ sim_op_error(sim);
return;
}
@@ -696,7 +663,7 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
op->current = 1;
- sim->simop_source = g_timeout_add(0, sim_op_retrieve_next, modem);
+ sim->simop_source = g_timeout_add(0, sim_op_retrieve_next, sim);
if (op->cache && imsi) {
char *path = g_strdup_printf(SIM_CACHE_PATH, imsi, op->id);
@@ -717,25 +684,23 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
static void sim_op_write_cb(const struct ofono_error *error, void *data)
{
- struct ofono_modem *modem = data;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = data;
struct sim_file_op *op = g_queue_pop_head(sim->simop_q);
ofono_sim_file_write_cb_t cb = op->cb;
if (g_queue_get_length(sim->simop_q) > 0)
- sim->simop_source = g_timeout_add(0, sim_op_next, modem);
+ sim->simop_source = g_timeout_add(0, sim_op_next, sim);
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
- cb(modem, 1, op->userdata);
+ cb(1, op->userdata);
else
- cb(modem, 0, op->userdata);
+ cb(0, op->userdata);
sim_file_op_free(op);
}
-static gboolean sim_op_check_cached(struct ofono_modem *modem)
+static gboolean sim_op_check_cached(struct ofono_sim *sim)
{
- struct sim_manager_data *sim = modem->sim_manager;
char *imsi = sim->imsi;
struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
ofono_sim_file_read_cb_t cb = op->cb;
@@ -786,7 +751,7 @@ static gboolean sim_op_check_cached(struct ofono_modem *modem)
if (error_type != OFONO_ERROR_TYPE_NO_ERROR) {
ret = TRUE;
- cb(modem, 0, 0, 0, 0, 0, 0, 0);
+ cb(0, 0, 0, 0, 0, 0, 0);
goto cleanup;
}
@@ -798,7 +763,7 @@ static gboolean sim_op_check_cached(struct ofono_modem *modem)
goto cleanup;
for (record = 0; record < file_length / record_length; record++) {
- cb(modem, 1, structure, file_length, record + 1,
+ cb(1, structure, file_length, record + 1,
&buffer[record * record_length], record_length,
op->userdata);
}
@@ -816,8 +781,7 @@ cleanup:
static gboolean sim_op_next(gpointer user_data)
{
- struct ofono_modem *modem = user_data;
- struct sim_manager_data *sim = modem->sim_manager;
+ struct ofono_sim *sim = user_data;
struct sim_file_op *op;
sim->simop_source = 0;
@@ -828,35 +792,35 @@ static gboolean sim_op_next(gpointer user_data)
op = g_queue_peek_head(sim->simop_q);
if (op->is_read == TRUE) {
- if (sim_op_check_cached(modem)) {
+ if (sim_op_check_cached(sim)) {
op = g_queue_pop_head(sim->simop_q);
sim_file_op_free(op);
if (g_queue_get_length(sim->simop_q) > 0)
sim->simop_source =
- g_timeout_add(0, sim_op_next, modem);
+ g_timeout_add(0, sim_op_next, sim);
return FALSE;
}
- sim->ops->read_file_info(modem, op->id, sim_op_info_cb, modem);
+ sim->driver->read_file_info(sim, op->id, sim_op_info_cb, sim);
} else {
switch (op->structure) {
case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
- sim->ops->write_file_transparent(modem, op->id, 0,
+ sim->driver->write_file_transparent(sim, op->id, 0,
op->length, op->buffer,
- sim_op_write_cb, modem);
+ sim_op_write_cb, sim);
break;
case OFONO_SIM_FILE_STRUCTURE_FIXED:
- sim->ops->write_file_linear(modem, op->id, op->current,
+ sim->driver->write_file_linear(sim, op->id, op->current,
op->length, op->buffer,
- sim_op_write_cb, modem);
+ sim_op_write_cb, sim);
break;
case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
- sim->ops->write_file_cyclic(modem, op->id,
+ sim->driver->write_file_cyclic(sim, op->id,
op->length, op->buffer,
- sim_op_write_cb, modem);
+ sim_op_write_cb, sim);
break;
default:
ofono_error("Unrecognized file structure, "
@@ -869,22 +833,21 @@ static gboolean sim_op_next(gpointer user_data)
return FALSE;
}
-int ofono_sim_read(struct ofono_modem *modem, int id,
+int ofono_sim_read(struct ofono_sim *sim, int id,
ofono_sim_file_read_cb_t cb, void *data)
{
- struct sim_manager_data *sim = modem->sim_manager;
struct sim_file_op *op;
if (!cb)
return -1;
- if (modem->sim_manager == NULL)
+ if (sim == NULL)
return -1;
- if (!sim->ops)
+ if (!sim->driver)
return -1;
- if (!sim->ops->read_file_info)
+ if (!sim->driver->read_file_info)
return -1;
/* TODO: We must first check the EFust table to see whether
@@ -904,17 +867,16 @@ int ofono_sim_read(struct ofono_modem *modem, int id,
g_queue_push_tail(sim->simop_q, op);
if (g_queue_get_length(sim->simop_q) == 1)
- sim->simop_source = g_timeout_add(0, sim_op_next, modem);
+ sim->simop_source = g_timeout_add(0, sim_op_next, sim);
return 0;
}
-int ofono_sim_write(struct ofono_modem *modem, int id,
+int ofono_sim_write(struct ofono_sim *sim, int id,
ofono_sim_file_write_cb_t cb,
enum ofono_sim_file_structure structure, int record,
const unsigned char *data, int length, void *userdata)
{
- struct sim_manager_data *sim = modem->sim_manager;
struct sim_file_op *op;
gconstpointer fn = NULL;
@@ -924,18 +886,18 @@ int ofono_sim_write(struct ofono_modem *modem, int id,
if (sim == NULL)
return -1;
- if (!sim->ops)
+ if (!sim->driver)
return -1;
switch (structure) {
case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
- fn = sim->ops->write_file_transparent;
+ fn = sim->driver->write_file_transparent;
break;
case OFONO_SIM_FILE_STRUCTURE_FIXED:
- fn = sim->ops->write_file_linear;
+ fn = sim->driver->write_file_linear;
break;
case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
- fn = sim->ops->write_file_cyclic;
+ fn = sim->driver->write_file_cyclic;
break;
default:
ofono_error("Unrecognized file structure, this can't happen");
@@ -961,153 +923,289 @@ int ofono_sim_write(struct ofono_modem *modem, int id,
g_queue_push_tail(sim->simop_q, op);
if (g_queue_get_length(sim->simop_q) == 1)
- sim->simop_source = g_timeout_add(0, sim_op_next, modem);
+ sim->simop_source = g_timeout_add(0, sim_op_next, sim);
return 0;
}
-static void initialize_sim_manager(struct ofono_modem *modem)
+const char *ofono_sim_get_imsi(struct ofono_sim *sim)
{
- DBusConnection *conn = ofono_dbus_get_connection();
+ if (sim == NULL)
+ return NULL;
- if (!g_dbus_register_interface(conn, modem->path,
- SIM_MANAGER_INTERFACE,
- sim_manager_methods,
- sim_manager_signals,
- NULL, modem,
- sim_manager_destroy)) {
- ofono_error("Could not register SIMManager interface");
- sim_manager_destroy(modem);
+ return sim->imsi;
+}
- return;
- }
+static void remove_all_watches(struct ofono_sim *sim)
+{
+ struct sim_ready_watch *watch;
+ GSList *c;
- ofono_debug("SIMManager interface for modem: %s created",
- modem->path);
+ for (c = sim->ready_watches; c; c = c->next) {
+ watch = c->data;
- ofono_modem_add_interface(modem, SIM_MANAGER_INTERFACE);
+ if (watch->destroy)
+ watch->destroy(watch->data);
- ofono_sim_ready_notify_register(modem, sim_ready);
+ g_free(watch);
+ }
- /* Perform SIM initialization according to 3GPP 31.102 Section 5.1.1.2
- * The assumption here is that if sim manager is being initialized,
- * then sim commands are implemented, and the sim manager is then
- * responsible for checking the PIN, reading the IMSI and signaling
- * SIM ready condition.
- *
- * The procedure according to 31.102 is roughly:
- * Read EFecc
- * Read EFli and EFpl
- * SIM Pin check
- * Read EFust
- * Read EFest
- * Read IMSI
- *
- * At this point we signal the SIM ready condition and allow
- * arbitrary files to be written or read, assuming their presence
- * in the EFust
- */
- sim_retrieve_imsi(modem);
+ g_slist_free(sim->ready_watches);
+ sim->ready_watches = NULL;
}
-const char *ofono_sim_get_imsi(struct ofono_modem *modem)
+unsigned int ofono_sim_add_ready_watch(struct ofono_sim *sim,
+ ofono_sim_ready_notify_cb_t notify,
+ void *data, ofono_destroy_func destroy)
{
- if (modem->sim_manager == NULL)
- return NULL;
+ struct sim_ready_watch *watch;
- return modem->sim_manager->imsi;
-}
+ DBG("%p", sim);
-int ofono_sim_ready_notify_register(struct ofono_modem *modem,
- ofono_sim_ready_notify_cb_t cb)
-{
- if (modem->sim_manager == NULL)
- return -1;
+ if (sim == NULL)
+ return 0;
+
+ if (notify == NULL)
+ return 0;
- modem->sim_manager->ready_notify =
- g_slist_append(modem->sim_manager->ready_notify, cb);
+ watch = g_new0(struct sim_ready_watch, 1);
- return 0;
+ watch->id = ++sim->next_ready_watch_id;
+ watch->notify = notify;
+ watch->destroy = destroy;
+ watch->data = data;
+
+ sim->ready_watches = g_slist_prepend(sim->ready_watches, watch);
+
+ DBG("id: %u", watch->id);
+
+ return watch->id;
}
-void ofono_sim_ready_notify_unregister(struct ofono_modem *modem,
- ofono_sim_ready_notify_cb_t cb)
+void ofono_sim_remove_ready_watch(struct ofono_sim *sim, unsigned int id)
{
- if (modem->sim_manager == NULL)
+ struct sim_ready_watch *watch;
+ GSList *p;
+ GSList *c;
+
+ if (sim == NULL)
return;
- modem->sim_manager->ready_notify =
- g_slist_remove(modem->sim_manager->ready_notify, cb);
+ DBG("%p, %u", sim, id);
+
+ p = NULL;
+ c = sim->ready_watches;
+
+ while (c) {
+ watch = c->data;
+
+ if (watch->id != id) {
+ p = c;
+ c = c->next;
+ continue;
+ }
+
+ if (p)
+ p->next = c->next;
+ else
+ sim->ready_watches = c->next;
+
+ if (watch->destroy)
+ watch->destroy(watch->data);
+
+ g_free(watch);
+ g_slist_free_1(c);
+
+ return;
+ }
}
-int ofono_sim_get_ready(struct ofono_modem *modem)
+int ofono_sim_get_ready(struct ofono_sim *sim)
{
- if (modem->sim_manager == NULL)
+ if (sim == NULL)
return 0;
- if (modem->sim_manager->ready == TRUE)
+ if (sim->ready == TRUE)
return 1;
return 0;
}
-void ofono_sim_set_ready(struct ofono_modem *modem)
+void ofono_sim_set_ready(struct ofono_sim *sim)
{
GSList *l;
- if (modem->sim_manager == NULL)
+ if (sim == NULL)
return;
- if (modem->sim_manager->ready == TRUE)
+ if (sim->ready == TRUE)
return;
- modem->sim_manager->ready = TRUE;
+ sim->ready = TRUE;
- for (l = modem->sim_manager->ready_notify; l; l = l->next) {
- ofono_sim_ready_notify_cb_t cb = l->data;
+ for (l = sim->ready_watches; l; l = l->next) {
+ struct sim_ready_watch *watch = l->data;
- cb(modem);
+ watch->notify(watch->data);
}
}
-int ofono_sim_manager_register(struct ofono_modem *modem,
- struct ofono_sim_ops *ops)
+int ofono_sim_driver_register(const struct ofono_sim_driver *d)
{
- if (modem == NULL)
- return -1;
- if (modem->sim_manager == NULL)
- return -1;
-
- if (ops == NULL)
- return -1;
+ DBG("driver: %p, name: %s", d, d->name);
- modem->sim_manager->ops = ops;
+ if (d->probe == NULL)
+ return -EINVAL;
- initialize_sim_manager(modem);
+ g_drivers = g_slist_prepend(g_drivers, (void *)d);
return 0;
}
-void ofono_sim_manager_unregister(struct ofono_modem *modem)
+void ofono_sim_driver_unregister(const struct ofono_sim_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ g_drivers = g_slist_remove(g_drivers, (void *)d);
+}
+
+static void sim_unregister(struct ofono_atom *atom)
{
DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(atom);
+ const char *path = __ofono_atom_get_path(atom);
- g_dbus_unregister_interface(conn, modem->path,
+ g_dbus_unregister_interface(conn, path,
SIM_MANAGER_INTERFACE);
ofono_modem_remove_interface(modem, SIM_MANAGER_INTERFACE);
}
-void ofono_sim_manager_init(struct ofono_modem *modem)
+static void sim_remove(struct ofono_atom *atom)
+{
+ struct ofono_sim *sim = __ofono_atom_get_data(atom);
+
+ DBG("atom: %p", atom);
+
+ if (sim == NULL)
+ return;
+
+ if (sim->driver && sim->driver->remove)
+ sim->driver->remove(sim);
+
+ if (sim->imsi) {
+ g_free(sim->imsi);
+ sim->imsi = NULL;
+ }
+
+ if (sim->own_numbers) {
+ g_slist_foreach(sim->own_numbers, (GFunc)g_free, NULL);
+ g_slist_free(sim->own_numbers);
+ sim->own_numbers = NULL;
+ }
+
+ if (sim->simop_source) {
+ g_source_remove(sim->simop_source);
+ sim->simop_source = 0;
+ }
+
+ if (sim->simop_q) {
+ g_queue_foreach(sim->simop_q, (GFunc)sim_file_op_free, NULL);
+ g_queue_free(sim->simop_q);
+ sim->simop_q = NULL;
+ }
+
+ g_free(sim);
+}
+
+struct ofono_sim *ofono_sim_create(struct ofono_modem *modem,
+ const char *driver,
+ void *data)
{
- modem->sim_manager = sim_manager_create();
+ struct ofono_sim *sim;
+ GSList *l;
+
+ if (driver == NULL)
+ return NULL;
+
+ sim = g_try_new0(struct ofono_sim, 1);
+
+ if (sim == NULL)
+ return NULL;
+
+ sim->driver_data = data;
+ sim->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_SIM,
+ sim_remove, sim);
+
+ for (l = g_drivers; l; l = l->next) {
+ const struct ofono_sim_driver *drv = l->data;
+
+ if (g_strcmp0(drv->name, driver))
+ continue;
+
+ if (drv->probe(sim) < 0)
+ continue;
+
+ sim->driver = drv;
+ break;
+ }
+
+ return sim;
}
-void ofono_sim_manager_exit(struct ofono_modem *modem)
+void ofono_sim_register(struct ofono_sim *sim)
{
- if (modem->sim_manager == NULL)
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(sim->atom);
+ const char *path = __ofono_atom_get_path(sim->atom);
+
+ if (!g_dbus_register_interface(conn, path,
+ SIM_MANAGER_INTERFACE,
+ sim_methods, sim_signals, NULL,
+ sim, NULL)) {
+ ofono_error("Could not create %s interface",
+ SIM_MANAGER_INTERFACE);
+
return;
+ }
+
+ ofono_modem_add_interface(modem, SIM_MANAGER_INTERFACE);
+
+ __ofono_atom_register(sim->atom, sim_unregister);
+
+ ofono_sim_add_ready_watch(sim, sim_ready, sim, NULL);
+
+ /* Perform SIM initialization according to 3GPP 31.102 Section 5.1.1.2
+ * The assumption here is that if sim manager is being initialized,
+ * then sim commands are implemented, and the sim manager is then
+ * responsible for checking the PIN, reading the IMSI and signaling
+ * SIM ready condition.
+ *
+ * The procedure according to 31.102 is roughly:
+ * Read EFecc
+ * Read EFli and EFpl
+ * SIM Pin check
+ * Read EFust
+ * Read EFest
+ * Read IMSI
+ *
+ * At this point we signal the SIM ready condition and allow
+ * arbitrary files to be written or read, assuming their presence
+ * in the EFust
+ */
+ sim_retrieve_imsi(sim);
+}
- g_free(modem->sim_manager);
+void ofono_sim_remove(struct ofono_sim *sim)
+{
+ __ofono_atom_free(sim->atom);
+}
- modem->sim_manager = NULL;
+void ofono_sim_set_data(struct ofono_sim *sim, void *data)
+{
+ sim->driver_data = data;
+}
+
+void *ofono_sim_get_data(struct ofono_sim *sim)
+{
+ return sim->driver_data;
}