From: Jukka Saunamaki <jukka.saunam...@nokia.com>

Using ofono_sim_ready_notify().
---
 drivers/isimodem/debug.c |   30 +++
 drivers/isimodem/debug.h |    3 +
 drivers/isimodem/sim.c   |  558 +++++++++++++++++++++++++++++++++++++++++++---
 drivers/isimodem/sim.h   |   50 ++++-
 4 files changed, 605 insertions(+), 36 deletions(-)

diff --git a/drivers/isimodem/debug.c b/drivers/isimodem/debug.c
index d226c51..f9ae6fe 100644
--- a/drivers/isimodem/debug.c
+++ b/drivers/isimodem/debug.c
@@ -48,6 +48,7 @@ const char *pn_resource_name(int value)
                _(PN_CALL);
                _(PN_SMS);
                _(PN_SIM);
+               _(PN_SECURITY);
                _(PN_MTC);
                _(PN_GSS);
                _(PN_GPDS);
@@ -377,18 +378,41 @@ const char *sim_message_id_name(enum sim_message_id value)
                _(SIM_IMSI_RESP_READ_IMSI);
                _(SIM_SERV_PROV_NAME_REQ);
                _(SIM_SERV_PROV_NAME_RESP);
+               _(SIM_DYNAMIC_FLAGS_REQ);
+               _(SIM_DYNAMIC_FLAGS_RESP);
                _(SIM_READ_FIELD_REQ);
                _(SIM_READ_FIELD_RESP);
                _(SIM_SMS_REQ);
                _(SIM_SMS_RESP);
+               _(SIM_STATUS_REQ);
+               _(SIM_STATUS_RESP);
                _(SIM_PB_REQ_SIM_PB_READ);
                _(SIM_PB_RESP_SIM_PB_READ);
+               _(SIM_SERVER_READY_IND);
                _(SIM_IND);
                _(SIM_COMMON_MESSAGE);
        }
        return "SIM_<UNKNOWN>";
 }
 
+const char *sec_message_id_name(enum sec_message_id value)
+{
+       switch (value) {
+               _(SEC_CODE_STATE_REQ);
+               _(SEC_CODE_STATE_OK_RESP);
+               _(SEC_CODE_STATE_FAIL_RESP);
+               _(SEC_CODE_CHANGE_REQ);
+               _(SEC_CODE_CHANGE_OK_RESP);
+               _(SEC_CODE_CHANGE_FAIL_RESP);
+               _(SEC_CODE_VERIFY_REQ);
+               _(SEC_CODE_VERIFY_OK_RESP);
+               _(SEC_CODE_VERIFY_FAIL_RESP);
+               _(SEC_STATE_REQ);
+               _(SEC_STATE_RESP);
+       }
+       return "SEC_<UNKNOWN>";
+}
+
 const char *sim_subblock_name(enum sim_subblock value)
 {
        switch (value) {
@@ -1069,6 +1093,12 @@ void sim_debug(const void *restrict buf, size_t len, 
void *data)
        hex_dump(sim_message_id_name(m[0]), m, len);
 }
 
+void sec_debug(const void *restrict buf, size_t len, void *data)
+{
+       const uint8_t *m = buf;
+       hex_dump(sec_message_id_name(m[0]), m, len);
+}
+
 void info_debug(const void *restrict buf, size_t len, void *data)
 {
        const uint8_t *m = buf;
diff --git a/drivers/isimodem/debug.h b/drivers/isimodem/debug.h
index f03f4ec..f0b34ae 100644
--- a/drivers/isimodem/debug.h
+++ b/drivers/isimodem/debug.h
@@ -49,6 +49,8 @@ const char *sim_isi_cause_name(enum sim_isi_cause value);
 const char *sim_message_id_name(enum sim_message_id value);
 const char *sim_subblock_name(enum sim_subblock value);
 
+const char *sec_message_id_name(enum sec_message_id value);
+
 const char *info_isi_cause_name(enum info_isi_cause value);
 const char *info_message_id_name(enum info_message_id value);
 const char *info_subblock_name(enum info_subblock value);
@@ -78,6 +80,7 @@ void ss_debug(const void *restrict buf, size_t len, void 
*data);
 void mtc_debug(const void *restrict buf, size_t len, void *data);
 void sms_debug(const void *restrict buf, size_t len, void *data);
 void sim_debug(const void *restrict buf, size_t len, void *data);
+void sec_debug(const void *restrict buf, size_t len, void *data);
 void info_debug(const void *restrict buf, size_t len, void *data);
 void call_debug(const void *restrict buf, size_t len, void *data);
 void net_debug(const void *restrict buf, size_t len, void *data);
diff --git a/drivers/isimodem/sim.c b/drivers/isimodem/sim.c
index e2ea275..833cbee 100644
--- a/drivers/isimodem/sim.c
+++ b/drivers/isimodem/sim.c
@@ -45,7 +45,9 @@
 
 struct sim_data {
        GIsiClient *client;
-       gboolean registered;
+       GIsiClient *sec_client;
+       enum ofono_sim_password_type passwd_state;
+       gboolean ready;
 };
 
 struct file_info {
@@ -319,6 +321,7 @@ static gboolean imsi_resp_cb(GIsiClient *client,
        goto out;
 
 error:
+       DBG("IMSI error");
        CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
 
 out:
@@ -335,12 +338,12 @@ static void isi_read_imsi(struct ofono_sim *sim,
                SIM_IMSI_REQ_READ_IMSI,
                READ_IMSI
        };
+       DBG("");
 
        if (!cbd)
                goto error;
 
-       if (g_isi_request_make(sd->client, msg, sizeof(msg),
-                               SIM_TIMEOUT,
+       if (g_isi_request_make(sd->client, msg, sizeof(msg), SIM_TIMEOUT,
                                imsi_resp_cb, cbd))
                return;
 
@@ -349,50 +352,325 @@ error:
        g_free(cbd);
 }
 
-static void isi_sim_register(struct ofono_sim *sim)
+static void isi_query_passwd_state(struct ofono_sim *sim,
+                                       ofono_sim_passwd_cb_t cb, void *data)
 {
        struct sim_data *sd = ofono_sim_get_data(sim);
+       enum ofono_sim_password_type passwd_state = sd->passwd_state;
 
-       if (!sd->registered) {
-               sd->registered = TRUE;
-               ofono_sim_register(sim);
-               ofono_sim_inserted_notify(sim, TRUE);
+       DBG("passwd_state %u", passwd_state);
+
+       if (passwd_state == OFONO_SIM_PASSWORD_INVALID) {
+               CALLBACK_WITH_FAILURE(cb, -1, data);
+               return;
        }
+
+       if (!sd->ready && passwd_state == OFONO_SIM_PASSWORD_NONE)
+               passwd_state = OFONO_SIM_PASSWORD_INVALID;
+
+       CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
 }
 
-static gboolean read_hplmn_resp_cb(GIsiClient *client,
+static gboolean sec_code_verify_resp(GIsiClient *client,
                                        const void *restrict data, size_t len,
                                        uint16_t object, void *opaque)
 {
        const unsigned char *msg = data;
-       struct ofono_sim *sim = opaque;
+       struct isi_cb_data *cbd = opaque;
+       ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+       struct ofono_sim *sim = cbd->user;
+       struct sim_data *sd = ofono_sim_get_data(sim);
 
-       if (!msg) {
-               DBG("ISI client error: %d", g_isi_client_error(client));
-               return TRUE;
+       DBG("");
+
+       if (len >= 1 && msg[0] == SEC_CODE_VERIFY_OK_RESP) {
+               sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
+               CALLBACK_WITH_SUCCESS(cb, cbd->data);
+               goto done;
        }
 
-       if (len < 3 || msg[0] != SIM_NETWORK_INFO_RESP || msg[1] != READ_HPLMN)
-               return FALSE;
+       if (len >= 2 && msg[0] == SEC_CODE_VERIFY_FAIL_RESP &&
+                       msg[1] == SEC_CAUSE_CODE_BLOCKED)
+               sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
 
-       if (msg[2] != SIM_SERV_NOTREADY)
-               isi_sim_register(sim);
+       DBG("verify failure %s", !msg ? "(timeout)" : "");
+       CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+done:
+       g_free(cbd);
 
        return TRUE;
 }
 
+static void isi_send_passwd(struct ofono_sim *sim, const char *passwd,
+                               ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+       struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+
+       unsigned char msg[2 + SEC_CODE_MAX_LENGTH + 1] = {
+               SEC_CODE_VERIFY_REQ,
+               SEC_CODE_PIN,
+       };
+       int len = 2 + strlen(passwd) + 1;
+
+       DBG("");
+
+       if (!cbd)
+               goto error;
+
+       strcpy((char *)msg + 2, passwd);
 
-static void isi_read_hplmn(struct ofono_sim *sim)
+       if (g_isi_request_make(sd->sec_client, msg, len, SIM_TIMEOUT,
+                               sec_code_verify_resp, cbd))
+               return;
+
+error:
+       g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void isi_reset_passwd(struct ofono_sim *sim,
+                               const char *puk, const char *passwd,
+                               ofono_sim_lock_unlock_cb_t cb, void *data)
 {
        struct sim_data *sd = ofono_sim_get_data(sim);
+       struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+       enum ofono_sim_password_type passwd_type = OFONO_SIM_PASSWORD_SIM_PIN;
+       unsigned char msg[2 + 2 * (SEC_CODE_MAX_LENGTH + 1)] = {
+               SEC_CODE_VERIFY_REQ,
+       };
 
-       const unsigned char req[] = {
-               SIM_NETWORK_INFO_REQ,
-               READ_HPLMN, 0
+       DBG("");
+
+       if (!cbd)
+               goto error;
+
+       if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+               msg[1] = SEC_CODE_PIN;
+       else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+               msg[1] = SEC_CODE_PIN2;
+       else
+               goto error;
+
+       strcpy((char *)&msg[2], puk);
+       strcpy((char *)&msg[2 + SEC_CODE_MAX_LENGTH + 1], passwd);
+
+       if (g_isi_request_make(sd->sec_client, msg, sizeof(msg), SIM_TIMEOUT,
+                               sec_code_verify_resp, cbd))
+               return;
+
+error:
+       g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, data);
+}
+
+
+/* ISI callback: Enable/disable PIN */
+static gboolean pin_enable_resp_cb(GIsiClient *client,
+                               const void *restrict data,
+                               size_t len, uint16_t object, void *opaque)
+{
+       const unsigned char *msg = data;
+       struct isi_cb_data *cbd = opaque;
+       ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+
+       DBG("");
+
+       if (len < 1 || msg[0] != SEC_CODE_STATE_OK_RESP)
+               CALLBACK_WITH_FAILURE(cb, cbd->data);
+       else
+               CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+       g_free(cbd);
+
+       return TRUE;
+}
+
+static void isi_lock(struct ofono_sim *sim,
+               enum ofono_sim_password_type passwd_type,
+               int enable, const char *passwd,
+               ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+       struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+       unsigned char msg[3 + SEC_CODE_MAX_LENGTH + 1] = {
+               SEC_CODE_STATE_REQ,
        };
 
-       g_isi_request_make(sd->client, req, sizeof(req), SIM_TIMEOUT,
-                               read_hplmn_resp_cb, sim);
+       if (!cbd)
+               goto error;
+
+       DBG("enable %d pintype %d pass %s", enable, passwd_type, passwd);
+
+       if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+               msg[1] = SEC_CODE_PIN;
+       else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+               msg[1] = SEC_CODE_PIN2;
+       else
+               goto error;
+
+       if (enable)
+               msg[2] = SEC_CODE_ENABLE;
+       else
+               msg[2] = SEC_CODE_DISABLE;
+
+       strcpy((char *)&msg[3], passwd);
+
+       if (g_isi_request_make(sd->sec_client, msg, sizeof(msg),
+                               SIM_TIMEOUT, pin_enable_resp_cb, cbd))
+               return;
+
+error:
+       g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, data);
+}
+
+
+
+/* ISI callback: PIN state (enabled/disabled) query */
+static gboolean sec_code_change_resp(GIsiClient *client,
+                                       const void *restrict data, size_t len,
+                                       uint16_t object, void *opaque)
+{
+       const unsigned char *msg = data;
+       struct isi_cb_data *cbd = opaque;
+       ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+
+       if (len < 1)
+               goto failure;
+
+       if (msg[0] != SEC_CODE_CHANGE_OK_RESP) {
+               if (msg[0] == SEC_CODE_CHANGE_FAIL_RESP && len >= 2)
+                       DBG("SEC_CODE_CHANGE_FAIL_RESP(cause=%02x)", msg[1]);
+               goto failure;
+       }
+
+       CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+       goto done;
+
+failure:
+       CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+done:
+       g_free(cbd);
+
+       return TRUE;
+}
+
+
+static void isi_change_passwd(struct ofono_sim *sim,
+                               enum ofono_sim_password_type passwd_type,
+                               const char *old, const char *new,
+                               ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+       struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+       unsigned char msg[2 + 2 * (SEC_CODE_MAX_LENGTH + 1)] = {
+               SEC_CODE_CHANGE_REQ,
+       };
+
+       DBG("passwd_type %d", passwd_type);
+
+       if (!cbd)
+               goto error;
+
+       if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+               msg[1] = SEC_CODE_PIN;
+       else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+               msg[1] = SEC_CODE_PIN2;
+       else
+               goto error;
+
+       strcpy((char *)&msg[2], old);
+       strcpy((char *)&msg[2 + SEC_CODE_MAX_LENGTH + 1], new);
+
+       if (g_isi_request_make(sd->sec_client, msg, sizeof(msg),
+                               SIM_TIMEOUT, sec_code_change_resp, cbd))
+               return;
+
+error:
+       g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, data);
+}
+
+
+/* ISI callback: PIN state (enabled/disabled) query */
+static gboolean sec_code_state_resp_cb(GIsiClient *client,
+                                       const void *restrict data, size_t len,
+                                       uint16_t object, void *opaque)
+{
+       const unsigned char *msg = data;
+       struct isi_cb_data *cbd = opaque;
+       ofono_sim_locked_cb_t cb = cbd->cb;
+       int locked;
+
+       if (msg == NULL || len < 4)
+               goto failure;
+
+       if (msg[0] != SEC_CODE_STATE_OK_RESP)
+               goto failure;
+
+       DBG("sec state: %02x", msg[1]);
+
+       if (msg[1] == SEC_CODE_ENABLE)
+               locked = 1;
+       else if (msg[1] == SEC_CODE_DISABLE)
+               locked = 0;
+       else
+               goto failure;
+
+       CALLBACK_WITH_SUCCESS(cb, locked, cbd->data);
+
+       goto done;
+
+failure:
+       CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+
+done:
+       g_free(cbd);
+
+       return TRUE;
+}
+
+static void isi_query_locked(struct ofono_sim *sim,
+                               enum ofono_sim_password_type passwd_type,
+                               ofono_sim_locked_cb_t cb, void *data)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+       struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+
+       unsigned char msg[] = {
+               SEC_CODE_STATE_REQ,
+               0,
+               SEC_CODE_STATE_QUERY
+       };
+
+       DBG("");
+
+       if (!cbd)
+               goto error;
+
+       if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN)
+               msg[1] = SEC_CODE_PIN;
+       else if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+               msg[1] = SEC_CODE_PIN2;
+       else
+               goto error;
+
+       if (g_isi_request_make(sd->sec_client, msg, sizeof(msg),
+                               SIM_TIMEOUT, sec_code_state_resp_cb, cbd))
+               return;
+
+error:
+       g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, -1, data);
 }
 
 static void sim_ind_cb(GIsiClient *client,
@@ -403,19 +681,200 @@ static void sim_ind_cb(GIsiClient *client,
        struct sim_data *sd = ofono_sim_get_data(sim);
        const unsigned char *msg = data;
 
-       if (sd->registered)
+       uint8_t servicetype;
+       uint8_t status;
+       uint8_t state;
+       uint8_t cause;
+
+       DBG("");
+       if (!msg || len < 5 ||
+               (msg[0] != SIM_IND && msg[0] != SIM_SERVER_READY_IND))
                return;
 
+       servicetype = msg[1];
+       status = msg[2];
+       state = msg[3];
+       cause = msg[4];
+
+       if (servicetype == SIM_ST_PIN &&
+               status == SIM_SERV_PIN_VERIFY_REQUIRED) {
+               sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
+               sd->ready = FALSE;
+               ofono_sim_inserted_notify(sim, TRUE);
+       } else if (status == SIM_SERV_SIM_BLOCKED) {
+               sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
+               sd->ready = FALSE;
+               ofono_sim_inserted_notify(sim, TRUE);
+       } else if (servicetype == SIM_ST_INFO &&
+               status == SIM_SERV_INIT_OK) {
+               sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
+               ofono_sim_inserted_notify(sim, TRUE);
+       } else if (status == SIM_SERV_SIM_DISCONNECTED) {
+               sd->passwd_state = OFONO_SIM_PASSWORD_INVALID;
+               sd->ready = FALSE;
+               ofono_sim_inserted_notify(sim, FALSE);
+       }
+}
+
+static void sim_server_ready_ind_cb(GIsiClient *client,
+                                       const void *restrict data, size_t len,
+                                       uint16_t object, void *opaque)
+{
+       struct ofono_sim *sim = opaque;
+       struct sim_data *sd = ofono_sim_get_data(sim);
+       const unsigned char *msg = data;
+
+       DBG("");
+
+       if (!msg || len < 5 || msg[0] != SIM_SERVER_READY_IND)
+               return;
+
+       sd->ready = TRUE;
+
+       ofono_sim_ready_notify(sim);
+}
+
+static gboolean isi_sim_read_dyn_flags_resp(GIsiClient *client,
+                               const void *restrict data, size_t len,
+                               uint16_t object, void *opaque)
+{
+       const unsigned char *msg = data;
+       struct ofono_sim *sim = opaque;
+       struct sim_data *sd = ofono_sim_get_data(sim);
+
+       if (!msg)
+               return TRUE;
+
+       if (len < 2 || msg[0] != SIM_DYNAMIC_FLAGS_RESP)
+               return FALSE;
+
+       if (msg[1] != READ_DYN_FLAGS || msg[2] == SIM_SERV_NOTREADY)
+               return TRUE;
+
+       sd->ready = TRUE;
+
+       ofono_sim_ready_notify(sim);
+
+       return TRUE;
+}
+
+static void isi_sim_read_dyn_flags_req(struct ofono_sim *sim)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+
+       unsigned char req[] = {
+               SIM_DYNAMIC_FLAGS_REQ,
+               READ_DYN_FLAGS,
+               0
+       };
+
+       g_isi_send(sd->client, req, sizeof(req), SIM_TIMEOUT,
+                       isi_sim_read_dyn_flags_resp, sim, NULL);
+}
+
+static gboolean sec_state_resp_cb(GIsiClient *client,
+                               const void *restrict data, size_t len,
+                               uint16_t object, void *opaque)
+{
+       const unsigned char *msg = data;
+       struct ofono_sim *sim = opaque;
+       struct sim_data *sd = ofono_sim_get_data(sim);
+       ofono_bool_t inserted = FALSE;
+
+       DBG("");
+
+       if (!msg) {
+               DBG("ISI client error: %d", g_isi_client_error(client));
+               return TRUE;
+       }
+       if (len < 2 || msg[0] != SEC_STATE_RESP)
+               return FALSE;
+
+       if (!sd)
+               return TRUE;
+
        switch (msg[1]) {
-       case SIM_ST_PIN:
-               isi_sim_register(sim);
+       case SEC_STARTUP_OK:
+               DBG("SEC_STARTUP_OK");
+               sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
+               inserted = TRUE;
+               /* Check if SIM server is already ready */
+               isi_sim_read_dyn_flags_req(sim);
+               break;
+       case SEC_CAUSE_PIN_REQUIRED:
+               DBG("SEC_CAUSE_PIN_REQUIRED");
+               sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
+               inserted = TRUE;
+               break;
+       case SEC_CAUSE_PUK_REQUIRED:
+               DBG("SEC_CAUSE_PUK_REQUIRED");
+               sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
+               inserted = TRUE;
                break;
-       case SIM_ST_INFO:
-               isi_read_hplmn(sim);
+       case SEC_CAUSE_NO_SIM:
+               DBG("SEC_CAUSE_NO_SIM");
+               break;
+       case SEC_CAUSE_INVALID_SIM:
+               DBG("SEC_CAUSE_INVALID_SIM");
+               break;
+       case SEC_CAUSE_SIM_REJECTED:
+               DBG("SEC_CAUSE_SIM_REJECTED");
+               break;
+       default:
                break;
        }
+
+       ofono_sim_inserted_notify(sim, inserted);
+
+       return TRUE;
+}
+
+static void isi_sec_state_req(struct ofono_sim *sim)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+
+       unsigned char req[] = {
+               SEC_STATE_REQ,
+               0,
+               0
+       };
+
+       g_isi_request_make(sd->sec_client, req, sizeof(req), SIM_TIMEOUT,
+                       sec_state_resp_cb, sim);
+}
+
+static gboolean sim_status_resp_cb(GIsiClient *client,
+                                       const void *restrict data, size_t len,
+                                       uint16_t object, void *opaque)
+{
+       const unsigned char *msg = data;
+       struct ofono_sim *sim = opaque;
+
+       if (!msg || len < 3)
+               return TRUE;
+
+       if (msg[0] == SIM_STATUS_RESP && msg[1] == SIM_ST_CARD_STATUS &&
+                       msg[2] != SIM_SERV_SIM_DISCONNECTED)
+               /* We probably have a SIM. Now get PIN/PUK status  */
+               isi_sec_state_req(sim); /* Try Sec-server first */
+
+       return TRUE;
 }
 
+static void isi_sim_status_req(struct ofono_sim *sim)
+{
+       struct sim_data *sd = ofono_sim_get_data(sim);
+
+       const unsigned char req[] = {
+               SIM_STATUS_REQ,
+               SIM_ST_CARD_STATUS
+       };
+
+       g_isi_request_make(sd->client, req, sizeof(req), SIM_TIMEOUT,
+                       sim_status_resp_cb, sim);
+}
+
+
 static void sim_reachable_cb(GIsiClient *client, gboolean alive,
                                uint16_t object, void *opaque)
 {
@@ -433,9 +892,13 @@ static void sim_reachable_cb(GIsiClient *client, gboolean 
alive,
                g_isi_version_minor(client));
 
        g_isi_subscribe(client, SIM_IND, sim_ind_cb, opaque);
+       g_isi_subscribe(client, SIM_SERVER_READY_IND,
+                       sim_server_ready_ind_cb, opaque);
 
-       /* Check if SIM is ready. */
-       isi_read_hplmn(sim);
+       ofono_sim_register(sim);
+
+       /* Check if we have a SIM */
+       isi_sim_status_req(sim);
 }
 
 static int isi_sim_probe(struct ofono_sim *sim, unsigned int vendor,
@@ -443,23 +906,41 @@ static int isi_sim_probe(struct ofono_sim *sim, unsigned 
int vendor,
 {
        GIsiModem *idx = user;
        struct sim_data *sd = g_try_new0(struct sim_data, 1);
+       GIsiClient *client = NULL;
+       GIsiClient *sec_client = NULL;
        const char *debug = getenv("OFONO_ISI_DEBUG");
 
        if (!sd)
-               return -ENOMEM;
+               goto error;
 
-       sd->client = g_isi_client_create(idx, PN_SIM);
-       if (!sd->client)
-               return -ENOMEM;
+       client = g_isi_client_create(idx, PN_SIM);
+       if (!client)
+               goto error;
+
+       sec_client = g_isi_client_create(idx, PN_SECURITY);
+       if (!sec_client)
+               goto error;
+
+       sd->client = client;
+       sd->sec_client = sec_client;
+       sd->passwd_state = OFONO_SIM_PASSWORD_INVALID;
 
        ofono_sim_set_data(sim, sd);
 
-       if (debug && (strcmp(debug, "all") == 0 || strcmp(debug, "sim") == 0))
+       if (debug && (!strcmp(debug, "all") || !strcmp(debug, "sim"))) {
                g_isi_client_set_debug(sd->client, sim_debug, NULL);
+               g_isi_client_set_debug(sd->sec_client, sec_debug, NULL);
+       }
 
        g_isi_verify(sd->client, sim_reachable_cb, sim);
 
        return 0;
+
+error:
+       g_isi_client_destroy(client);
+       g_isi_client_destroy(sec_client);
+
+       return -ENOMEM;
 }
 
 static void isi_sim_remove(struct ofono_sim *sim)
@@ -471,6 +952,7 @@ static void isi_sim_remove(struct ofono_sim *sim)
 
        ofono_sim_set_data(sim, NULL);
        g_isi_client_destroy(data->client);
+       g_isi_client_destroy(data->sec_client);
        g_free(data);
 }
 
@@ -486,6 +968,12 @@ static struct ofono_sim_driver driver = {
        .write_file_linear      = isi_write_file_linear,
        .write_file_cyclic      = isi_write_file_cyclic,
        .read_imsi              = isi_read_imsi,
+       .query_passwd_state     = isi_query_passwd_state,
+       .send_passwd            = isi_send_passwd,
+       .reset_passwd           = isi_reset_passwd,
+       .lock                   = isi_lock,
+       .change_passwd          = isi_change_passwd,
+       .query_locked           = isi_query_locked,
 };
 
 void isi_sim_init()
diff --git a/drivers/isimodem/sim.h b/drivers/isimodem/sim.h
index e1450b7..a47835a 100644
--- a/drivers/isimodem/sim.h
+++ b/drivers/isimodem/sim.h
@@ -27,9 +27,12 @@ extern "C" {
 #endif
 
 #define PN_SIM                 0x09
+#define PN_SECURITY             0x08
 #define SIM_TIMEOUT            5
 #define SIM_MAX_IMSI_LENGTH    15
 
+#define SEC_CODE_MAX_LENGTH    0x0A
+
 enum sim_isi_cause {
        SIM_SERV_NOT_AVAIL = 0x00,
        SIM_SERV_OK = 0x01,
@@ -131,29 +134,74 @@ enum sim_message_id {
        SIM_IMSI_RESP_READ_IMSI = 0x1E,
        SIM_SERV_PROV_NAME_REQ = 0x21,
        SIM_SERV_PROV_NAME_RESP = 0x22,
+       SIM_DYNAMIC_FLAGS_REQ = 0x29,
+       SIM_DYNAMIC_FLAGS_RESP = 0x2A,
        SIM_READ_FIELD_REQ = 0xBA,
        SIM_READ_FIELD_RESP = 0xBB,
        SIM_SMS_REQ = 0xBC,
        SIM_SMS_RESP = 0xBD,
+       SIM_STATUS_REQ = 0xC0,
+       SIM_STATUS_RESP = 0xC1,
        SIM_PB_REQ_SIM_PB_READ = 0xDC,
        SIM_PB_RESP_SIM_PB_READ = 0xDD,
+       SIM_SERVER_READY_IND = 0xED,
        SIM_IND = 0xEF,
        SIM_COMMON_MESSAGE = 0xF0
 };
 
 enum sim_service_type {
+       SIM_ST_CARD_STATUS = 0x00,
        SIM_ST_PIN = 0x01,
        SIM_ST_ALL_SERVICES = 0x05,
        SIM_ST_INFO = 0x0D,
-       SIM_ST_READ_SERV_PROV_NAME = 0x2C,
        SIM_PB_READ = 0x0F,
+       SIM_ST_READ_SERV_PROV_NAME = 0x2C,
        READ_IMSI = 0x2D,
        READ_HPLMN = 0x2F,
+       READ_DYN_FLAGS = 0x35,
        READ_PARAMETER = 0x52,
        UPDATE_PARAMETER = 0x53,
        ICC = 0x66,
 };
 
+enum sec_message_id {
+       SEC_CODE_STATE_REQ = 0x01,
+       SEC_CODE_STATE_OK_RESP = 0x02,
+       SEC_CODE_STATE_FAIL_RESP = 0x03,
+       SEC_CODE_CHANGE_REQ = 0x04,
+       SEC_CODE_CHANGE_OK_RESP = 0x05,
+       SEC_CODE_CHANGE_FAIL_RESP = 0x06,
+       SEC_CODE_VERIFY_REQ = 0x07,
+       SEC_CODE_VERIFY_OK_RESP = 0x08,
+       SEC_CODE_VERIFY_FAIL_RESP = 0x09,
+       SEC_STATE_REQ = 0x11,
+       SEC_STATE_RESP = 0x12,
+};
+
+enum sec_code_id_info {
+       SEC_CODE_PIN = 0x02,
+       SEC_CODE_PUK = 0x03,
+       SEC_CODE_PIN2 = 0x04,
+       SEC_CODE_PUK2 = 0x05,
+};
+
+enum sec_code_state_info {
+       SEC_CODE_DISABLE = 0x00,
+       SEC_CODE_ENABLE = 0x01,
+       SEC_CODE_STATE_QUERY = 0x04,
+};
+
+enum sec_state_cause_info {
+       SEC_CAUSE_PIN_REQUIRED = 0x02,
+       SEC_CAUSE_PUK_REQUIRED = 0x03,
+       SEC_STARTUP_OK = 0x05,
+       SEC_STARTUP_ONGOING = 0x07,
+       SEC_CAUSE_CODE_BLOCKED = 0x08,
+       SEC_CAUSE_NO_SIM = 0x16,
+       SEC_CAUSE_SIM_REJECTED = 0x1A,
+       SEC_CAUSE_INVALID_SIM = 0x1E,
+};
+
 #ifdef __cplusplus
 };
 #endif
-- 
1.7.0.4

_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to