summaryrefslogtreecommitdiffstats
path: root/drivers/atmodem/sim.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/atmodem/sim.c')
-rw-r--r--drivers/atmodem/sim.c199
1 files changed, 176 insertions, 23 deletions
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index a2aebb89..66e951ec 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -41,20 +41,22 @@
static const char *crsm_prefix[] = { "+CRSM:", NULL };
static const char *cnum_prefix[] = { "+CNUM:", NULL };
-static void at_crsm_len_cb(gboolean ok, GAtResult *result, gpointer user_data)
+static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
- ofono_sim_file_len_cb_t cb = cbd->cb;
+ ofono_sim_file_info_cb_t cb = cbd->cb;
struct ofono_error error;
const guint8 *response;
gint sw1, sw2, len;
+ int flen, rlen;
+ enum ofono_simfile_struct str;
- dump_response("at_crsm_len_cb", ok, result);
+ dump_response("at_crsm_info_cb", ok, result);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
- cb(&error, -1, cbd->data);
+ cb(&error, -1, -1, -1, cbd->data);
return;
}
@@ -63,29 +65,38 @@ static void at_crsm_len_cb(gboolean ok, GAtResult *result, gpointer user_data)
if (!g_at_result_iter_next(&iter, "+CRSM:")) {
DECLARE_FAILURE(e);
- cb(&e, -1, cbd->data);
+ cb(&e, -1, -1, -1, cbd->data);
return;
}
g_at_result_iter_next_number(&iter, &sw1);
- g_at_result_iter_next_number(&iter, &len);
+ g_at_result_iter_next_number(&iter, &sw2);
if (!g_at_result_iter_next_hexstring(&iter, &response, &len) ||
(sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92) ||
- (sw1 == 0x90 && sw2 != 0x00) || len < 14) {
+ (sw1 == 0x90 && sw2 != 0x00) ||
+ len < 14 || response[6] != 0x04 ||
+ (response[13] == 0x01 && len < 15)) {
DECLARE_FAILURE(e);
- cb(&e, -1, cbd->data);
+ cb(&e, -1, -1, -1, cbd->data);
return;
}
- ofono_debug("crsm_len_cb: %02x, %02x, %i", sw1, sw2, len);
+ ofono_debug("crsm_info_cb: %02x, %02x, %i", sw1, sw2, len);
+
+ flen = (response[2] << 8) | response[3];
+ str = response[13];
+ if (str == 0x01)
+ rlen = response[14];
+ else
+ rlen = 0;
- cb(&error, (response[2] << 8) | response[3], cbd->data);
+ cb(&error, flen, str, rlen, cbd->data);
}
-static void at_sim_read_file_len(struct ofono_modem *modem, int fileid,
- ofono_sim_file_len_cb_t cb,
+static void at_sim_read_info(struct ofono_modem *modem, int fileid,
+ ofono_sim_file_info_cb_t cb,
void *data)
{
struct at_data *at = ofono_modem_userdata(modem);
@@ -97,7 +108,7 @@ static void at_sim_read_file_len(struct ofono_modem *modem, int fileid,
snprintf(buf, sizeof(buf), "AT+CRSM=192,%i,0,0,15", fileid);
if (g_at_chat_send(at->parser, buf, crsm_prefix,
- at_crsm_len_cb, cbd, g_free) > 0)
+ at_crsm_info_cb, cbd, g_free) > 0)
return;
error:
@@ -106,11 +117,12 @@ error:
{
DECLARE_FAILURE(error);
- cb(&error, -1, data);
+ cb(&error, -1, -1, -1, data);
}
}
-static void at_crsm_cb(gboolean ok, GAtResult *result, gpointer user_data)
+static void at_crsm_read_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
@@ -119,7 +131,7 @@ static void at_crsm_cb(gboolean ok, GAtResult *result, gpointer user_data)
const guint8 *response;
gint sw1, sw2, len;
- dump_response("at_crsm_cb", ok, result);
+ dump_response("at_crsm_read_cb", ok, result);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
@@ -147,14 +159,14 @@ static void at_crsm_cb(gboolean ok, GAtResult *result, gpointer user_data)
return;
}
- ofono_debug("crsm_cb: %02x, %02x, %d", sw1, sw2, len);
+ ofono_debug("crsm_read_cb: %02x, %02x, %d", sw1, sw2, len);
cb(&error, response, len, cbd->data);
}
-static void at_sim_read_file(struct ofono_modem *modem, int fileid, int start,
- int length, ofono_sim_read_cb_t cb,
- void *data)
+static void at_sim_read_binary(struct ofono_modem *modem, int fileid,
+ int start, int length,
+ ofono_sim_read_cb_t cb, void *data)
{
struct at_data *at = ofono_modem_userdata(modem);
struct cb_data *cbd = cb_data_new(modem, cb, data);
@@ -166,7 +178,34 @@ static void at_sim_read_file(struct ofono_modem *modem, int fileid, int start,
snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid,
start >> 8, start & 0xff, length);
if (g_at_chat_send(at->parser, buf, crsm_prefix,
- at_crsm_cb, cbd, g_free) > 0)
+ at_crsm_read_cb, cbd, g_free) > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, NULL, 0, data);
+ }
+}
+
+static void at_sim_read_record(struct ofono_modem *modem, int fileid,
+ int record, int length,
+ ofono_sim_read_cb_t cb, void *data)
+{
+ struct at_data *at = ofono_modem_userdata(modem);
+ struct cb_data *cbd = cb_data_new(modem, cb, data);
+ char buf[64];
+
+ if (!cbd)
+ goto error;
+
+ snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
+ record + 1, length);
+ if (g_at_chat_send(at->parser, buf, crsm_prefix,
+ at_crsm_read_cb, cbd, g_free) > 0)
return;
error:
@@ -179,6 +218,117 @@ error:
}
}
+static void at_crsm_update_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ GAtResultIter iter;
+ ofono_generic_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ gint sw1, sw2;
+
+ dump_response("at_crsm_update_cb", ok, result);
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CRSM:")) {
+ DECLARE_FAILURE(e);
+
+ cb(&e, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_next_number(&iter, &sw1);
+ g_at_result_iter_next_number(&iter, &sw2);
+ if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
+ (sw1 == 0x90 && sw2 != 0x00)) {
+ DECLARE_FAILURE(e);
+
+ cb(&e, cbd->data);
+ return;
+ }
+
+ ofono_debug("crsm_update_cb: %02x, %02x", sw1, sw2);
+
+ cb(&error, cbd->data);
+}
+
+static void at_sim_update_binary(struct ofono_modem *modem, int fileid,
+ int start, int length,
+ const unsigned char *value,
+ ofono_generic_cb_t cb, void *data)
+{
+ struct at_data *at = ofono_modem_userdata(modem);
+ struct cb_data *cbd = cb_data_new(modem, cb, data);
+ char *buf = g_try_new(char, 36 + length * 2);
+ int len, ret;
+
+ if (!cbd || !buf)
+ goto error;
+
+ len = sprintf(buf, "AT+CRSM=214,%i,%i,%i,%i,", fileid,
+ start >> 8, start & 0xff, length);
+ for (; length; length--)
+ len += sprintf(buf + len, "%02hhx", *value++);
+ ret = g_at_chat_send(at->parser, buf, crsm_prefix,
+ at_crsm_update_cb, cbd, g_free);
+
+ g_free(buf);
+
+ if (ret > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, data);
+ }
+}
+
+static void at_sim_update_record(struct ofono_modem *modem, int fileid,
+ int record, int length,
+ const unsigned char *value,
+ ofono_generic_cb_t cb, void *data)
+{
+ struct at_data *at = ofono_modem_userdata(modem);
+ struct cb_data *cbd = cb_data_new(modem, cb, data);
+ char *buf = g_try_new(char, 36 + length * 2);
+ int len, ret;
+
+ if (!cbd || !buf)
+ goto error;
+
+ len = sprintf(buf, "AT+CRSM=220,%i,%i,4,%i,", fileid,
+ record + 1, length);
+ for (; length; length--)
+ len += sprintf(buf + len, "%02hhx", *value++);
+ ret = g_at_chat_send(at->parser, buf, crsm_prefix,
+ at_crsm_update_cb, cbd, g_free);
+
+ g_free(buf);
+
+ if (ret > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, data);
+ }
+}
+
static void at_cimi_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -317,8 +467,11 @@ error:
}
static struct ofono_sim_ops ops = {
- .read_file_len = at_sim_read_file_len,
- .read_file = at_sim_read_file,
+ .read_file_info = at_sim_read_info,
+ .read_file_transparent = at_sim_read_binary,
+ .read_file_linear = at_sim_read_record,
+ .write_file_transparent = at_sim_update_binary,
+ .write_file_linear = at_sim_update_record,
.read_imsi = at_read_imsi,
.read_own_numbers = at_read_msisdn,
};