From: Cedric Jehasse <cedric.jehasse(a)softathome.com>
---
drivers/qmimodem/sim.c | 155 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 139 insertions(+), 16 deletions(-)
diff --git a/drivers/qmimodem/sim.c b/drivers/qmimodem/sim.c
index 197da50..e05aac8 100644
--- a/drivers/qmimodem/sim.c
+++ b/drivers/qmimodem/sim.c
@@ -45,6 +45,8 @@ struct sim_data {
uint8_t app_type;
uint8_t passwd_state;
int retries[OFONO_SIM_PASSWORD_INVALID];
+ struct cb_data *pin_cbd;
+ guint pin_timeout;
};
static int create_fileid_data(uint8_t app_type, int fileid,
@@ -355,25 +357,12 @@ static void card_setup(const struct qmi_uim_slot_info *slot,
data->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
}
-static void get_card_status_cb(struct qmi_result *result, void *user_data)
+static void handle_card_status(struct sim_data *data, const void *ptr)
{
- struct ofono_sim *sim = user_data;
- struct sim_data *data = ofono_sim_get_data(sim);
- const void *ptr;
- const struct qmi_uim_card_status *status;
- uint16_t len, offset;
+ const struct qmi_uim_card_status *status = ptr;
+ uint16_t offset;
uint8_t i;
- DBG("");
-
- if (qmi_result_set_error(result, NULL))
- goto done;
-
- ptr = qmi_result_get(result, QMI_UIM_RESULT_CARD_STATUS, &len);
- if (!ptr)
- goto done;
-
- status = ptr;
offset = sizeof(struct qmi_uim_card_status);
for (i = 0; i < status->num_slot; i++) {
@@ -401,6 +390,25 @@ static void get_card_status_cb(struct qmi_result *result, void
*user_data)
card_setup(slot, info1, info2, data);
}
}
+}
+
+static void get_card_status_cb(struct qmi_result *result, void *user_data)
+{
+ struct ofono_sim *sim = user_data;
+ struct sim_data *data = ofono_sim_get_data(sim);
+ const void *ptr;
+ uint16_t len;
+
+ DBG("");
+
+ if (qmi_result_set_error(result, NULL))
+ goto done;
+
+ ptr = qmi_result_get(result, QMI_UIM_RESULT_CARD_STATUS, &len);
+ if (!ptr)
+ goto done;
+
+ handle_card_status(data, ptr);
done:
ofono_sim_register(sim);
@@ -415,6 +423,33 @@ done:
}
}
+static void card_status_ind(struct qmi_result *result, void *user_data)
+{
+ struct ofono_sim *sim = user_data;
+ struct sim_data *data = ofono_sim_get_data(sim);
+ const void *ptr;
+ uint16_t len;
+
+ DBG("");
+
+ ptr = qmi_result_get(result, QMI_UIM_RESULT_CARD_STATUS, &len);
+ if (!ptr)
+ return;
+
+ handle_card_status(data, ptr);
+
+ if (data->passwd_state == OFONO_SIM_PASSWORD_NONE && data->pin_cbd) {
+ /*send_passwd pending*/
+ struct cb_data *cbd = data->pin_cbd;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ g_source_remove(data->pin_timeout);
+ data->pin_cbd = NULL;
+ data->pin_timeout = 0;
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ g_free(cbd);
+ }
+}
+
static void event_registration_cb(struct qmi_result *result, void *user_data)
{
struct ofono_sim *sim = user_data;
@@ -455,6 +490,8 @@ static void create_uim_cb(struct qmi_service *service, void
*user_data)
}
data->uim = qmi_service_ref(service);
+ qmi_service_register(data->uim, QMI_UIM_CARD_STATUS_IND,
+ card_status_ind, sim, NULL);
param = qmi_param_new_uint32(QMI_UIM_PARAM_EVENT_MASK, mask);
if (!param)
@@ -508,6 +545,91 @@ static void qmi_sim_remove(struct ofono_sim *sim)
g_free(data);
}
+static gboolean send_passwd_timeout(gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct sim_data *data = ofono_sim_get_data(cbd->user);
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+
+ DBG("");
+
+ data->pin_cbd = cbd;
+ data->pin_timeout = 0;
+
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ g_free(cbd);
+
+ return FALSE;
+}
+
+static void send_passwd_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct sim_data *data = ofono_sim_get_data(cbd->user);
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+
+ DBG("");
+
+ if (qmi_result_set_error(result, NULL))
+ goto error;
+
+ /* wait for CARD_STATUS_IND */
+ if (data->passwd_state == OFONO_SIM_PASSWORD_NONE) {
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ } else {
+ data->pin_cbd = cbd;
+ data->pin_timeout = g_timeout_add_seconds(10, send_passwd_timeout,
+ user_data);
+ }
+
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ g_free(cbd);
+}
+
+static void qmi_send_passwd(struct ofono_sim *sim, const char *passwd,
+ ofono_sim_lock_unlock_cb_t cb, void *user_data)
+{
+ struct sim_data *data = ofono_sim_get_data(sim);
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+ struct qmi_param *param;
+ int len;
+ unsigned char passwd_data[16];
+ unsigned char aid_data[2] = { 0x06, 0x00 };
+
+ DBG("");
+
+ len = strlen(passwd);
+ if ((len - 3) > sizeof(passwd_data))
+ goto error;
+
+ param = qmi_param_new();
+ if (!param)
+ goto error;
+
+ passwd_data[0] = 0x01;
+ passwd_data[1] = len;
+ memcpy(&passwd_data[2], passwd, len);
+
+ qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
+ qmi_param_append(param, 0x02, len + 2, passwd_data);
+
+ cbd->user = sim;
+
+ if (qmi_service_send(data->uim, QMI_UIM_VERIFY_PIN, param,
+ send_passwd_cb, cbd, NULL) > 0)
+ return;
+
+ qmi_param_free(param);
+
+error:
+ CALLBACK_WITH_FAILURE(cb, user_data);
+
+ g_free(cbd);
+}
+
static struct ofono_sim_driver driver = {
.name = "qmimodem",
.probe = qmi_sim_probe,
@@ -518,6 +640,7 @@ static struct ofono_sim_driver driver = {
.read_file_cyclic = qmi_read_record,
.query_passwd_state = qmi_query_passwd_state,
.query_pin_retries = qmi_query_pin_retries,
+ .send_passwd = qmi_send_passwd,
};
void qmi_sim_init(void)
--
1.7.9.5