* [PATCH_v2 1/4] cdmamodem: Add sim driver implementation
2011-11-21 10:54 [PATCH_v2 0/4] Use sim atom with cdma modems Guillaume Zajac
@ 2011-11-21 10:54 ` Guillaume Zajac
2011-11-27 12:02 ` Denis Kenzior
2011-11-21 10:54 ` [PATCH_v2 2/4] simfs: Call callback with failure if driver is not implemented Guillaume Zajac
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Guillaume Zajac @ 2011-11-21 10:54 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 17205 bytes --]
---
Makefile.am | 3 +-
drivers/cdmamodem/cdmamodem.c | 2 +
drivers/cdmamodem/cdmamodem.h | 3 +
drivers/cdmamodem/sim.c | 582 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 589 insertions(+), 1 deletions(-)
create mode 100644 drivers/cdmamodem/sim.c
diff --git a/Makefile.am b/Makefile.am
index 337aeb7..db39000 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -273,7 +273,8 @@ builtin_sources += drivers/cdmamodem/cdmamodem.h \
drivers/cdmamodem/cdmamodem.c \
drivers/cdmamodem/voicecall.c \
drivers/cdmamodem/devinfo.c \
- drivers/cdmamodem/connman.c
+ drivers/cdmamodem/connman.c \
+ drivers/cdmamodem/sim.c
builtin_modules += huaweicdmamodem
builtin_sources += drivers/huaweicdmamodem/huaweicdmamodem.h \
diff --git a/drivers/cdmamodem/cdmamodem.c b/drivers/cdmamodem/cdmamodem.c
index 50908e3..771b408 100644
--- a/drivers/cdmamodem/cdmamodem.c
+++ b/drivers/cdmamodem/cdmamodem.c
@@ -37,6 +37,7 @@ static int cdmamodem_init(void)
cdma_voicecall_init();
cdma_devinfo_init();
cdma_connman_init();
+ cdma_sim_init();
return 0;
}
@@ -46,6 +47,7 @@ static void cdmamodem_exit(void)
cdma_voicecall_exit();
cdma_devinfo_exit();
cdma_connman_exit();
+ cdma_sim_exit();
}
OFONO_PLUGIN_DEFINE(cdmamodem, "CDMA AT modem driver", VERSION,
diff --git a/drivers/cdmamodem/cdmamodem.h b/drivers/cdmamodem/cdmamodem.h
index 3554705..53b617d 100644
--- a/drivers/cdmamodem/cdmamodem.h
+++ b/drivers/cdmamodem/cdmamodem.h
@@ -20,6 +20,7 @@
*/
#include <drivers/atmodem/atutil.h>
+#include <drivers/atmodem/vendor.h>
extern void cdma_voicecall_init(void);
extern void cdma_voicecall_exit(void);
@@ -27,3 +28,5 @@ extern void cdma_devinfo_init(void);
extern void cdma_devinfo_exit(void);
extern void cdma_connman_init(void);
extern void cdma_connman_exit(void);
+extern void cdma_sim_init(void);
+extern void cdma_sim_exit(void);
diff --git a/drivers/cdmamodem/sim.c b/drivers/cdmamodem/sim.c
new file mode 100644
index 0000000..26cd572
--- /dev/null
+++ b/drivers/cdmamodem/sim.c
@@ -0,0 +1,582 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/sim.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "cdmamodem.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+struct sim_data {
+ GAtChat *chat;
+ unsigned int vendor;
+ guint ready_id;
+};
+
+static const char *cpin_prefix[] = { "+CPIN:", NULL };
+static const char *clck_prefix[] = { "+CLCK:", NULL };
+static const char *huawei_cpin_prefix[] = { "^CPIN:", NULL };
+static const char *cpinr_prefixes[] = { "+CPINR:", "+CPINRE:", NULL };
+static const char *none_prefix[] = { NULL };
+
+static void cdma_cimi_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ GAtResultIter iter;
+ ofono_sim_imsi_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ const char *imsi;
+ int i;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, NULL, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ for (i = 0; i < g_at_result_num_response_lines(result); i++)
+ g_at_result_iter_next(&iter, NULL);
+
+ imsi = g_at_result_iter_raw_line(&iter);
+
+ DBG("cimi_cb: %s", imsi);
+
+ cb(&error, imsi, cbd->data);
+}
+
+static void cdma_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
+ void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct cb_data *cbd = cb_data_new(cb, data);
+
+ if (g_at_chat_send(sd->chat, "AT+CIMI", NULL,
+ cdma_cimi_cb, cbd, g_free) > 0)
+ return;
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, NULL, data);
+}
+
+static struct {
+ enum ofono_sim_password_type type;
+ const char *name;
+} const cdma_sim_name[] = {
+ { OFONO_SIM_PASSWORD_NONE, "READY" },
+ { OFONO_SIM_PASSWORD_SIM_PIN, "SIM PIN" },
+ { OFONO_SIM_PASSWORD_SIM_PUK, "SIM PUK" },
+ { OFONO_SIM_PASSWORD_PHSIM_PIN, "PH-SIM PIN" },
+ { OFONO_SIM_PASSWORD_PHFSIM_PIN, "PH-FSIM PIN" },
+ { OFONO_SIM_PASSWORD_PHFSIM_PUK, "PH-FSIM PUK" },
+ { OFONO_SIM_PASSWORD_SIM_PIN2, "SIM PIN2" },
+ { OFONO_SIM_PASSWORD_SIM_PUK2, "SIM PUK2" },
+ { OFONO_SIM_PASSWORD_PHNET_PIN, "PH-NET PIN" },
+ { OFONO_SIM_PASSWORD_PHNET_PUK, "PH-NET PUK" },
+ { OFONO_SIM_PASSWORD_PHNETSUB_PIN, "PH-NETSUB PIN" },
+ { OFONO_SIM_PASSWORD_PHNETSUB_PUK, "PH-NETSUB PUK" },
+ { OFONO_SIM_PASSWORD_PHSP_PIN, "PH-SP PIN" },
+ { OFONO_SIM_PASSWORD_PHSP_PUK, "PH-SP PUK" },
+ { OFONO_SIM_PASSWORD_PHCORP_PIN, "PH-CORP PIN" },
+ { OFONO_SIM_PASSWORD_PHCORP_PUK, "PH-CORP PUK" },
+};
+
+#define BUILD_PIN_RETRIES_ARRAY(passwd_types, passwd_types_cnt, retry) \
+ for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++) \
+ retry[i] = -1; \
+ \
+ for (i = 0; i < passwd_types_cnt; i++) { \
+ int val; \
+ \
+ if (!g_at_result_iter_next_number(&iter, &val)) \
+ goto error; \
+ \
+ retry[passwd_types[i]] = val; \
+ \
+ DBG("retry counter id=%d, val=%d", passwd_types[i], \
+ retry[passwd_types[i]]); \
+ } \
+
+static void huawei_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_sim_pin_retries_cb_t cb = cbd->cb;
+ const char *final = g_at_result_final_response(result);
+ GAtResultIter iter;
+ struct ofono_error error;
+ int retries[OFONO_SIM_PASSWORD_INVALID];
+ size_t i;
+ static enum ofono_sim_password_type password_types[] = {
+ OFONO_SIM_PASSWORD_SIM_PUK,
+ OFONO_SIM_PASSWORD_SIM_PIN,
+ OFONO_SIM_PASSWORD_SIM_PUK2,
+ OFONO_SIM_PASSWORD_SIM_PIN2,
+ };
+
+ decode_at_error(&error, final);
+
+ if (!ok) {
+ cb(&error, NULL, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "^CPIN:"))
+ goto error;
+
+ /* Skip status since we are not interested in this */
+ if (!g_at_result_iter_skip_next(&iter))
+ goto error;
+
+ /* Skip "overall counter" since we'll grab each one individually */
+ if (!g_at_result_iter_skip_next(&iter))
+ goto error;
+
+ BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
+ retries);
+
+ cb(&error, retries, cbd->data);
+
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+static void cdma_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_sim_pin_retries_cb_t cb = cbd->cb;
+ GAtResultIter iter;
+ struct ofono_error error;
+ int retries[OFONO_SIM_PASSWORD_INVALID];
+ size_t len = sizeof(cdma_sim_name) / sizeof(*cdma_sim_name);
+ size_t i;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, NULL, cbd->data);
+ return;
+ }
+
+ for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
+ retries[i] = -1;
+
+ g_at_result_iter_init(&iter, result);
+
+ /* Ignore +CPINRE results... */
+ while (g_at_result_iter_next(&iter, "+CPINR:")) {
+ const char *name;
+ int val;
+
+ if (!g_at_result_iter_next_unquoted_string(&iter, &name))
+ continue;
+
+ if (!g_at_result_iter_next_number(&iter, &val))
+ continue;
+
+ for (i = 1; i < len; i++) {
+ if (!strcmp(name, cdma_sim_name[i].name)) {
+ retries[i] = val;
+ break;
+ }
+ }
+ }
+
+ cb(&error, retries, cbd->data);
+}
+
+static void cdma_pin_retries_query(struct ofono_sim *sim,
+ ofono_sim_pin_retries_cb_t cb,
+ void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct cb_data *cbd = cb_data_new(cb, data);
+
+ DBG("");
+
+ switch (sd->vendor) {
+ case OFONO_VENDOR_HUAWEI:
+ if (g_at_chat_send(sd->chat, "AT^CPIN?", huawei_cpin_prefix,
+ huawei_cpin_cb, cbd, g_free) > 0)
+ return;
+ break;
+ default:
+ if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
+ cdma_cpinr_cb, cbd, g_free) > 0)
+ return;
+ break;
+ }
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, NULL, data);
+}
+
+static void cdma_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ GAtResultIter iter;
+ ofono_sim_passwd_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ const char *pin_required;
+ int pin_type = OFONO_SIM_PASSWORD_INVALID;
+ int i;
+ int len = sizeof(cdma_sim_name) / sizeof(*cdma_sim_name);
+ const char *final = g_at_result_final_response(result);
+
+ decode_at_error(&error, final);
+
+ if (!ok) {
+ cb(&error, -1, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CPIN:")) {
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_next_unquoted_string(&iter, &pin_required);
+
+
+ for (i = 0; i < len; i++) {
+ if (strcmp(pin_required, cdma_sim_name[i].name))
+ continue;
+
+ pin_type = cdma_sim_name[i].type;
+ break;
+ }
+
+ if (pin_type == OFONO_SIM_PASSWORD_INVALID) {
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+ return;
+ }
+
+ DBG("crsm_pin_cb: %s", pin_required);
+
+ cb(&error, pin_type, cbd->data);
+}
+
+static void cdma_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
+ void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct cb_data *cbd = cb_data_new(cb, data);
+
+ cbd->user = sim;
+
+ if (g_at_chat_send(sd->chat, "AT+CPIN?", cpin_prefix,
+ cdma_cpin_cb, cbd, g_free) > 0)
+ return;
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+}
+
+static void cdma_pin_send_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+ cb(&error, cbd->data);
+
+ g_free(cbd);
+}
+
+static void cdma_pin_send(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 cb_data *cbd = cb_data_new(cb, data);
+ char buf[64];
+ int ret;
+
+ cbd->user = sd;
+
+ snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
+
+ ret = g_at_chat_send(sd->chat, buf, none_prefix,
+ cdma_pin_send_cb, cbd, NULL);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (ret > 0)
+ return;
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void cdma_pin_send_puk(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 cb_data *cbd = cb_data_new(cb, data);
+ char buf[64];
+ int ret;
+
+ cbd->user = sd;
+
+ snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
+
+ ret = g_at_chat_send(sd->chat, buf, none_prefix,
+ cdma_pin_send_cb, cbd, NULL);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (ret > 0)
+ return;
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void cdma_lock_unlock_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ cb(&error, cbd->data);
+}
+
+static const char *const cdma_clck_cpwd_fac[] = {
+ [OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
+ [OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
+ [OFONO_SIM_PASSWORD_PHSIM_PIN] = "PS",
+ [OFONO_SIM_PASSWORD_PHFSIM_PIN] = "PF",
+ [OFONO_SIM_PASSWORD_PHNET_PIN] = "PN",
+ [OFONO_SIM_PASSWORD_PHNETSUB_PIN] = "PU",
+ [OFONO_SIM_PASSWORD_PHSP_PIN] = "PP",
+ [OFONO_SIM_PASSWORD_PHCORP_PIN] = "PC",
+};
+
+static void cdma_pin_enable(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 cb_data *cbd = cb_data_new(cb, data);
+ char buf[64];
+ int ret;
+ unsigned int len = sizeof(cdma_clck_cpwd_fac) / sizeof(*cdma_clck_cpwd_fac);
+
+ if (passwd_type >= len || cdma_clck_cpwd_fac[passwd_type] == NULL)
+ goto error;
+
+ snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
+ cdma_clck_cpwd_fac[passwd_type], enable ? 1 : 0, passwd);
+
+ ret = g_at_chat_send(sd->chat, buf, none_prefix,
+ cdma_lock_unlock_cb, cbd, g_free);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (ret > 0)
+ return;
+
+error:
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void cdma_change_passwd(struct ofono_sim *sim,
+ enum ofono_sim_password_type passwd_type,
+ const char *old_passwd, const char *new_passwd,
+ ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ char buf[64];
+ int ret;
+ unsigned int len = sizeof(cdma_clck_cpwd_fac) / sizeof(*cdma_clck_cpwd_fac);
+
+ if (passwd_type >= len ||
+ cdma_clck_cpwd_fac[passwd_type] == NULL)
+ goto error;
+
+ snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
+ cdma_clck_cpwd_fac[passwd_type], old_passwd, new_passwd);
+
+ ret = g_at_chat_send(sd->chat, buf, none_prefix,
+ cdma_lock_unlock_cb, cbd, g_free);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (ret > 0)
+ return;
+
+error:
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void cdma_lock_status_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ GAtResultIter iter;
+ ofono_sim_locked_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ int locked;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, -1, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CLCK:")) {
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+ return;
+ }
+
+ g_at_result_iter_next_number(&iter, &locked);
+
+ DBG("lock_status_cb: %i", locked);
+
+ cb(&error, locked, cbd->data);
+}
+
+static void cdma_pin_query_enabled(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 cb_data *cbd = cb_data_new(cb, data);
+ char buf[64];
+ unsigned int len = sizeof(cdma_clck_cpwd_fac) / sizeof(*cdma_clck_cpwd_fac);
+
+ if (passwd_type >= len || cdma_clck_cpwd_fac[passwd_type] == NULL)
+ goto error;
+
+ snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
+ cdma_clck_cpwd_fac[passwd_type]);
+
+ if (g_at_chat_send(sd->chat, buf, clck_prefix,
+ cdma_lock_status_cb, cbd, g_free) > 0)
+ return;
+
+error:
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+}
+
+static gboolean cdma_sim_register(gpointer user)
+{
+ struct ofono_sim *sim = user;
+
+ ofono_sim_register(sim);
+
+ return FALSE;
+}
+
+static int cdma_sim_probe(struct ofono_sim *sim, unsigned int vendor,
+ void *data)
+{
+ GAtChat *chat = data;
+ struct sim_data *sd;
+
+ sd = g_new0(struct sim_data, 1);
+ sd->chat = g_at_chat_clone(chat);
+ sd->vendor = vendor;
+
+ ofono_sim_set_data(sim, sd);
+ g_idle_add(cdma_sim_register, sim);
+
+ return 0;
+}
+
+static void cdma_sim_remove(struct ofono_sim *sim)
+{
+ struct sim_data *sd = ofono_sim_get_data(sim);
+
+ ofono_sim_set_data(sim, NULL);
+
+ g_at_chat_unref(sd->chat);
+ g_free(sd);
+}
+
+static struct ofono_sim_driver driver = {
+ .name = "cdmamodem",
+ .probe = cdma_sim_probe,
+ .remove = cdma_sim_remove,
+ .read_imsi = cdma_read_imsi,
+ .query_passwd_state = cdma_pin_query,
+ .query_pin_retries = cdma_pin_retries_query,
+ .send_passwd = cdma_pin_send,
+ .reset_passwd = cdma_pin_send_puk,
+ .lock = cdma_pin_enable,
+ .change_passwd = cdma_change_passwd,
+ .query_locked = cdma_pin_query_enabled,
+};
+
+void cdma_sim_init(void)
+{
+ ofono_sim_driver_register(&driver);
+}
+
+void cdma_sim_exit(void)
+{
+ ofono_sim_driver_unregister(&driver);
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH_v2 3/4] huaweicdma: Add SIM creation and set_online method driver
2011-11-21 10:54 [PATCH_v2 0/4] Use sim atom with cdma modems Guillaume Zajac
2011-11-21 10:54 ` [PATCH_v2 1/4] cdmamodem: Add sim driver implementation Guillaume Zajac
2011-11-21 10:54 ` [PATCH_v2 2/4] simfs: Call callback with failure if driver is not implemented Guillaume Zajac
@ 2011-11-21 10:54 ` Guillaume Zajac
2011-11-27 14:29 ` Denis Kenzior
2011-11-21 10:54 ` [PATCH_v2 4/4] sim: Get IMSI if sim state is OFONO_SIM_STATE_INSERTED Guillaume Zajac
3 siblings, 1 reply; 10+ messages in thread
From: Guillaume Zajac @ 2011-11-21 10:54 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 9052 bytes --]
---
plugins/huaweicdma.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 276 insertions(+), 7 deletions(-)
diff --git a/plugins/huaweicdma.c b/plugins/huaweicdma.c
index 4c83114..0fd9ef2 100644
--- a/plugins/huaweicdma.c
+++ b/plugins/huaweicdma.c
@@ -37,10 +37,28 @@
#include <ofono/cdma-netreg.h>
#include <ofono/cdma-connman.h>
#include <ofono/log.h>
+#include <ofono.h>
+
+#include <drivers/atmodem/atutil.h>
+#include <drivers/atmodem/vendor.h>
+
+static const char *none_prefix[] = { NULL };
+static const char *sysinfo_prefix[] = { "^SYSINFO:", NULL };
+
+enum {
+ SIM_STATE_VALID = 1,
+ SIM_STATE_EMBEDDED = 240,
+ SIM_STATE_NOT_EXISTENT = 255,
+};
struct huaweicdma_data {
GAtChat *modem;
GAtChat *pcui;
+ gboolean have_sim;
+ int sim_state;
+ guint sysinfo_poll_source;
+ guint sysinfo_poll_count;
+ struct cb_data *online_cbd;
};
static void huaweicdma_debug(const char *str, void *data)
@@ -79,6 +97,122 @@ static void huaweicdma_remove(struct ofono_modem *modem)
g_free(data);
}
+static void simst_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct huaweicdma_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+ int sim_state;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "^SIMST:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &sim_state))
+ return;
+
+ DBG("%d -> %d", data->sim_state, sim_state);
+
+ data->sim_state = sim_state;
+}
+
+static gboolean parse_sysinfo_result(GAtResult *result, int *srv_status,
+ int *srv_domain, int *sim_state)
+{
+ GAtResultIter iter;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "^SYSINFO:"))
+ return FALSE;
+
+ if (!g_at_result_iter_next_number(&iter, srv_status))
+ return FALSE;
+
+ if (!g_at_result_iter_next_number(&iter, srv_domain))
+ return FALSE;
+
+ if (!g_at_result_iter_skip_next(&iter))
+ return FALSE;
+
+ if (!g_at_result_iter_skip_next(&iter))
+ return FALSE;
+
+ if (!g_at_result_iter_next_number(&iter, sim_state))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void shutdown_device(struct huaweicdma_data *data)
+{
+ g_at_chat_cancel_all(data->modem);
+ g_at_chat_unregister_all(data->modem);
+
+ g_at_chat_unref(data->modem);
+ data->modem = NULL;
+
+ g_at_chat_cancel_all(data->pcui);
+ g_at_chat_unregister_all(data->pcui);
+
+ g_at_chat_unref(data->pcui);
+ data->pcui = NULL;
+}
+
+static gboolean sysinfo_enable_check(gpointer user_data);
+
+static void sysinfo_enable_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct huaweicdma_data *data = ofono_modem_get_data(modem);
+ int srv_status, srv_domain, sim_state;
+
+ if (!ok)
+ goto failure;
+
+ if (parse_sysinfo_result(result, &srv_status, &srv_domain,
+ &sim_state) == FALSE)
+ goto failure;
+
+ DBG("%d -> %d", data->sim_state, sim_state);
+
+ data->sim_state = sim_state;
+
+ if (sim_state == SIM_STATE_NOT_EXISTENT) {
+ data->sysinfo_poll_count++;
+
+ if (data->sysinfo_poll_count > 5)
+ goto failure;
+
+ data->sysinfo_poll_source = g_timeout_add_seconds(1,
+ sysinfo_enable_check, modem);
+ return;
+ }
+
+ data->have_sim = TRUE;
+ ofono_modem_set_powered(modem, TRUE);
+ return;
+
+failure:
+ shutdown_device(data);
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static gboolean sysinfo_enable_check(gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct huaweicdma_data *data = ofono_modem_get_data(modem);
+
+ data->sysinfo_poll_source = 0;
+
+ g_at_chat_send(data->pcui, "AT^SYSINFO", sysinfo_prefix,
+ sysinfo_enable_cb, modem, NULL);
+
+ return FALSE;
+}
+
static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -87,14 +221,18 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
DBG("");
if (!ok) {
- g_at_chat_unref(data->modem);
- data->modem = NULL;
-
- g_at_chat_unref(data->pcui);
- data->pcui = NULL;
+ shutdown_device(data);
+ ofono_modem_set_powered(modem, FALSE);
+ return;
}
- ofono_modem_set_powered(modem, ok);
+ /* Follow sim state changes */
+ g_at_chat_register(data->pcui, "^SIMST:", simst_notify,
+ FALSE, modem, NULL);
+
+ data->sysinfo_poll_count = 0;
+
+ sysinfo_enable_check(modem);
}
static GAtChat *open_device(struct ofono_modem *modem,
@@ -150,6 +288,8 @@ static int huaweicdma_enable(struct ofono_modem *modem)
g_at_chat_send(data->modem, "ATE0 &C0 +CMEE=1", NULL, NULL, NULL, NULL);
g_at_chat_send(data->pcui, "ATE0 &C0 +CMEE=1", NULL, NULL, NULL, NULL);
+ data->sim_state = SIM_STATE_NOT_EXISTENT;
+
g_at_chat_send(data->pcui, "AT+CFUN=1", NULL,
cfun_enable, modem, NULL);
@@ -191,18 +331,146 @@ static int huaweicdma_disable(struct ofono_modem *modem)
return -EINPROGRESS;
}
+
+static gboolean sysinfo_online_check(gpointer user_data);
+
+static void sysinfo_online_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct huaweicdma_data *data = user_data;
+ ofono_modem_online_cb_t cb = data->online_cbd->cb;
+ int srv_status, srv_domain, sim_state;
+
+ if (!ok)
+ goto failure;
+
+ if (parse_sysinfo_result(result, &srv_status, &srv_domain,
+ &sim_state) == FALSE)
+ goto failure;
+
+ DBG("%d -> %d", data->sim_state, sim_state);
+
+ data->sim_state = sim_state;
+
+ /* Valid service status and at minimum PS domain */
+ if (srv_status > 0 && srv_domain > 1) {
+ CALLBACK_WITH_SUCCESS(cb, data->online_cbd->data);
+ goto done;
+ }
+
+ switch (sim_state) {
+ case SIM_STATE_VALID:
+ case SIM_STATE_EMBEDDED:
+ CALLBACK_WITH_SUCCESS(cb, data->online_cbd->data);
+ goto done;
+ }
+
+ data->sysinfo_poll_count++;
+
+ if (data->sysinfo_poll_count > 15)
+ goto failure;
+
+ data->sysinfo_poll_source = g_timeout_add_seconds(2,
+ sysinfo_online_check, data);
+ return;
+
+failure:
+ CALLBACK_WITH_FAILURE(cb, data->online_cbd->data);
+
+done:
+ g_free(data->online_cbd);
+ data->online_cbd = NULL;
+}
+
+static gboolean sysinfo_online_check(gpointer user_data)
+{
+ struct huaweicdma_data *data = user_data;
+
+ data->sysinfo_poll_source = 0;
+
+ g_at_chat_send(data->pcui, "AT^SYSINFO", sysinfo_prefix,
+ sysinfo_online_cb, data, NULL);
+
+ return FALSE;
+}
+
+static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct huaweicdma_data *data = ofono_modem_get_data(modem);
+
+ if (!ok) {
+ ofono_modem_online_cb_t cb = data->online_cbd->cb;
+
+ CALLBACK_WITH_FAILURE(cb, data->online_cbd->data);
+
+ g_free(data->online_cbd);
+ data->online_cbd = NULL;
+ return;
+ }
+
+ data->sysinfo_poll_count = 0;
+
+ sysinfo_online_check(data);
+}
+
+static void set_offline_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_modem_online_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+ cb(&error, cbd->data);
+}
+
+static void huaweicdma_set_online(struct ofono_modem *modem,
+ ofono_bool_t online,
+ ofono_modem_online_cb_t cb, void *user_data)
+{
+ struct huaweicdma_data *data = ofono_modem_get_data(modem);
+
+ DBG("modem %p %s", modem, online ? "online" : "offline");
+
+ if (online == TRUE) {
+ data->online_cbd = cb_data_new(cb, user_data);
+
+ if (g_at_chat_send(data->pcui, "AT+CFUN=1", none_prefix,
+ set_online_cb, modem, NULL) > 0)
+ return;
+
+ g_free(data->online_cbd);
+ data->online_cbd = NULL;
+ } else {
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+
+ if (g_at_chat_send(data->pcui, "AT+CFUN=4", none_prefix,
+ set_offline_cb, cbd, g_free) > 0)
+ return;
+
+ g_free(cbd);
+ }
+
+ CALLBACK_WITH_FAILURE(cb, user_data);
+}
+
static void huaweicdma_pre_sim(struct ofono_modem *modem)
{
struct huaweicdma_data *data = ofono_modem_get_data(modem);
+ struct ofono_sim *sim;
DBG("%p", modem);
ofono_devinfo_create(modem, 0, "cdmamodem", data->pcui);
+ sim = ofono_sim_create(modem, OFONO_VENDOR_HUAWEI,
+ "cdmamodem", data->pcui);
+
+ if (sim && data->have_sim == TRUE)
+ ofono_sim_inserted_notify(sim, TRUE);
}
static void huaweicdma_post_sim(struct ofono_modem *modem)
{
- DBG("%p", modem);
}
static void huaweicdma_post_online(struct ofono_modem *modem)
@@ -222,6 +490,7 @@ static struct ofono_modem_driver huaweicdma_driver = {
.remove = huaweicdma_remove,
.enable = huaweicdma_enable,
.disable = huaweicdma_disable,
+ .set_online = huaweicdma_set_online,
.pre_sim = huaweicdma_pre_sim,
.post_sim = huaweicdma_post_sim,
.post_online = huaweicdma_post_online,
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread