Simplify sim handling by querying cpin state directly from
quectel_pre_sim().
The query is conducted by issuing a AT+CPIN?, where only CME errors are
catched by the command response handler. The +CPIN: <state> response is
instead catched by a listener.
The CME handler allows proper handling of the sim-busy and sim-not-
inserted states, which are returned as CME errors by the quectel
modems.
The +CPIN listener allows handling of both sim-locked and sim-ready
states. When the sim is not locked, the listener catches the +CPIN:
READY response from the query in quectel_pre_sim(). If the sim is
locked, the listener catched the +CPIN: READY indication received after
unlocking the sim.
---
plugins/quectel.c | 401 +++++++++++++++++-----------------------------
1 file changed, 149 insertions(+), 252 deletions(-)
diff --git a/plugins/quectel.c b/plugins/quectel.c
index a0e435b5..4c94d305 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -59,7 +59,6 @@
#include <drivers/atmodem/vendor.h>
static const char *cfun_prefix[] = { "+CFUN:", NULL };
-static const char *cpin_prefix[] = { "+CPIN:", NULL };
static const char *cbc_prefix[] = { "+CBC:", NULL };
static const char *qinistat_prefix[] = { "+QINISTAT:", NULL };
static const char *cgmm_prefix[] = { "UC15", "Quectel_M95", "Quectel_MC60",
@@ -84,21 +83,12 @@ enum quectel_model {
QUECTEL_MC60,
};
-enum quectel_state {
- QUECTEL_STATE_INITIALIZING = 0,
- QUECTEL_STATE_POST_SIM,
- QUECTEL_STATE_READY,
- QUECTEL_STATE_INITIALIZED,
-};
-
struct quectel_data {
GAtChat *modem;
GAtChat *aux;
enum ofono_vendor vendor;
enum quectel_model model;
- enum quectel_state state;
struct ofono_sim *sim;
- enum ofono_sim_state sim_state;
unsigned int sim_watch;
/* used by quectel uart driver */
@@ -531,213 +521,6 @@ static void dbus_hw_enable(struct ofono_modem *modem)
ofono_modem_add_interface(modem, dbus_hw_interface);
}
-static void qinistat_cb(gboolean ok, GAtResult *result, gpointer user_data)
-{
- struct ofono_modem *modem = user_data;
- struct quectel_data *data = ofono_modem_get_data(modem);
- GAtResultIter iter;
- int ready = 0;
- int status;
-
- DBG("%p", modem);
-
- g_at_result_iter_init(&iter, result);
-
- if (!g_at_result_iter_next(&iter, "+QINISTAT:"))
- return;
-
- if (!g_at_result_iter_next_number(&iter, &status))
- return;
-
- DBG("qinistat: %d", status);
-
- switch (data->model) {
- case QUECTEL_UC15:
- /* UC15 uses a bitmap of 1 + 2 + 4 = 7 */
- ready = 7;
- break;
- case QUECTEL_M95:
- case QUECTEL_MC60:
- /* M95 and MC60 uses a counter to 3 */
- ready = 3;
- break;
- case QUECTEL_UNKNOWN:
- ready = 0;
- break;
- }
-
- if (status != ready) {
- l_timeout_modify_ms(data->init_timeout, 500);
- return;
- }
-
- l_timeout_remove(data->init_timeout);
- data->init_timeout = NULL;
-
- if (data->sim_state == OFONO_SIM_STATE_READY) {
- /*
- * when initializing with a non-locked sim card, the sim atom
- * isn't created until now to avoid accessing it before the
- * modem is ready.
- *
- * call ofono_modem_set_powered() to make ofono call
- * quectel_pre_sim() where the sim atom is created.
- */
- ofono_modem_set_powered(modem, true);
- } else {
- /*
- * When initialized with a locked sim card, the modem is already
- * powered up, and the inserted signal has been sent to allow
- * the pin to be entered. So simply update the state, and notify
- * about the finished initialization below.
- */
- data->sim_state = OFONO_SIM_STATE_READY;
- }
-
- ofono_sim_initialized_notify(data->sim);
-
- /*
- * If quectel_post_sim() has not yet been called, then postpone atom
- * creation until it is called. Otherwise create the atoms now.
- */
- if (data->state != QUECTEL_STATE_POST_SIM) {
- data->state = QUECTEL_STATE_READY;
- return;
- }
-
- ofono_sms_create(modem, data->vendor, "atmodem", data->aux);
- ofono_phonebook_create(modem, data->vendor, "atmodem", data->aux);
- ofono_voicecall_create(modem, data->vendor, "atmodem", data->aux);
- ofono_call_volume_create(modem, data->vendor, "atmodem", data->aux);
- data->state = QUECTEL_STATE_INITIALIZED;
-}
-
-static void init_timer_cb(struct l_timeout *timeout, void *user_data)
-{
- struct ofono_modem *modem = user_data;
- struct quectel_data *data = ofono_modem_get_data(modem);
-
- DBG("%p", modem);
-
- g_at_chat_send(data->aux, "AT+QINISTAT", qinistat_prefix, qinistat_cb,
- modem, NULL);
-}
-
-static void sim_watch_cb(GAtResult *result, void *user_data)
-{
- struct ofono_modem *modem = user_data;
- struct quectel_data *data = ofono_modem_get_data(modem);
-
- DBG("%p", modem);
-
- g_at_chat_unregister(data->aux, data->sim_watch);
- data->sim_watch = 0;
-
- data->init_timeout = l_timeout_create_ms(500, init_timer_cb, modem,
NULL);
- if (!data->init_timeout) {
- close_serial(modem);
- return;
- }
-}
-
-static enum ofono_sim_state cme_parse(GAtResult *result)
-{
- struct ofono_error error;
-
- decode_at_error(&error, g_at_result_final_response(result));
-
- if (error.type != OFONO_ERROR_TYPE_CME)
- return OFONO_SIM_STATE_RESETTING;
-
- switch (error.error) {
- case 5:
- case 6:
- case 7:
- case 11:
- case 12:
- case 17:
- case 18:
- return OFONO_SIM_STATE_LOCKED_OUT;
- case 10:
- return OFONO_SIM_STATE_NOT_PRESENT;
- case 13:
- case 14:
- case 15:
- return OFONO_SIM_STATE_RESETTING;
- default:
- ofono_error("unknown cpin error: %i", error.error);
- return OFONO_SIM_STATE_RESETTING;
- }
-}
-
-static enum ofono_sim_state cpin_parse(GAtResult *result)
-{
- GAtResultIter iter;
- const char *cpin;
-
- g_at_result_iter_init(&iter, result);
-
- if (!g_at_result_iter_next(&iter, "+CPIN:"))
- return OFONO_SIM_STATE_RESETTING;
-
- g_at_result_iter_next_unquoted_string(&iter, &cpin);
-
- if (g_strcmp0(cpin, "NOT INSERTED") == 0)
- return OFONO_SIM_STATE_NOT_PRESENT;
-
- if (g_strcmp0(cpin, "READY") == 0)
- return OFONO_SIM_STATE_READY;
-
- return OFONO_SIM_STATE_LOCKED_OUT;
-}
-
-static void cpin_query(gboolean ok, GAtResult *result, gpointer user_data)
-{
- struct ofono_modem *modem = user_data;
- struct quectel_data *data = ofono_modem_get_data(modem);
-
- DBG("%p ok %i", modem, ok);
-
- if (ok)
- data->sim_state = cpin_parse(result);
- else
- data->sim_state = cme_parse(result);
-
- /* Turn off the radio. */
- g_at_chat_send(data->aux, "AT+CFUN=4", none_prefix, NULL, NULL, NULL);
-
- switch (data->sim_state) {
- case OFONO_SIM_STATE_LOCKED_OUT:
- ofono_modem_set_powered(modem, true);
- data->sim_watch = g_at_chat_register(data->aux, "+CPIN: READY",
- sim_watch_cb, FALSE,
- modem, NULL);
- if (!data->sim_watch) {
- ofono_error("failed to create sim watch");
- close_serial(modem);
- return;
- }
- break;
- case OFONO_SIM_STATE_READY:
- data->init_timeout = l_timeout_create_ms(500, init_timer_cb,
- modem, NULL);
- if (!data->init_timeout) {
- ofono_error("failed to create qinitstat timer");
- close_serial(modem);
- return;
- }
- break;
- case OFONO_SIM_STATE_RESETTING:
- case OFONO_SIM_STATE_INSERTED:
- g_at_chat_send(data->aux, "AT+CPIN?", cpin_prefix, cpin_query,
- modem, NULL);
- break;
- case OFONO_SIM_STATE_NOT_PRESENT:
- ofono_warn("%s: sim not present", ofono_modem_get_path(modem));
- ofono_modem_set_powered(modem, true);
- }
-}
-
static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -751,9 +534,8 @@ static void cfun_enable(gboolean ok, GAtResult *result,
gpointer user_data)
}
dbus_hw_enable(modem);
-
- g_at_chat_send(data->aux, "AT+CPIN?", cpin_prefix, cpin_query, modem,
- NULL);
+ g_at_chat_send(data->aux, "AT+CFUN=4", none_prefix, NULL, NULL, NULL);
+ ofono_modem_set_powered(modem, true);
}
static void cfun_query(gboolean ok, GAtResult *result, gpointer user_data)
@@ -1108,8 +890,6 @@ static int quectel_disable(struct ofono_modem *modem)
g_at_chat_send(data->aux, "AT+CFUN=0", cfun_prefix, cfun_disable, modem,
NULL);
- data->state = QUECTEL_STATE_INITIALIZING;
-
return -EINPROGRESS;
}
@@ -1143,27 +923,166 @@ static void quectel_set_online(struct ofono_modem
*modem, ofono_bool_t online,
g_free(cbd);
}
-static void quectel_pre_sim(struct ofono_modem *modem)
+static void qinistat_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
+ struct ofono_modem *modem = user_data;
struct quectel_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+ int ready = 0;
+ int status;
DBG("%p", modem);
- ofono_devinfo_create(modem, 0, "atmodem", data->aux);
- data->sim = ofono_sim_create(modem, data->vendor, "atmodem", data->aux);
- if (!data->sim)
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+QINISTAT:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &status))
+ return;
+
+ DBG("qinistat: %d", status);
+
+ switch (data->model) {
+ case QUECTEL_UC15:
+ /* UC15 uses a bitmap of 1 + 2 + 4 = 7 */
+ ready = 7;
+ break;
+ case QUECTEL_M95:
+ case QUECTEL_MC60:
+ /* M95 and MC60 uses a counter to 3 */
+ ready = 3;
+ break;
+ case QUECTEL_UNKNOWN:
+ ready = 0;
+ break;
+ }
+
+ if (status != ready) {
+ l_timeout_modify_ms(data->init_timeout, 500);
+ return;
+ }
+
+ l_timeout_remove(data->init_timeout);
+ data->init_timeout = NULL;
+
+ if (ofono_sim_get_state(data->sim) == OFONO_SIM_STATE_INSERTED)
+ ofono_sim_initialized_notify(data->sim);
+ else
+ ofono_sim_inserted_notify(data->sim, true);
+}
+
+static void init_timer_cb(struct l_timeout *timeout, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct quectel_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ g_at_chat_send(data->aux, "AT+QINISTAT", qinistat_prefix, qinistat_cb,
+ modem, NULL);
+}
+
+static void sim_watch_cb(GAtResult *result, void *user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct quectel_data *data = ofono_modem_get_data(modem);
+ enum ofono_sim_state state = ofono_sim_get_state(data->sim);
+ const char *path = ofono_modem_get_path(modem);
+ GAtResultIter iter;
+ const char *cpin;
+
+ DBG("%p", modem);
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CPIN:"))
return;
- switch (data->sim_state) {
- case OFONO_SIM_STATE_LOCKED_OUT:
- case OFONO_SIM_STATE_READY:
+ g_at_result_iter_next_unquoted_string(&iter, &cpin);
+
+ if (g_strcmp0(cpin, "NOT INSERTED") == 0) {
+ ofono_warn("%s: sim not present", path);
+ return;
+ }
+
+ if (g_strcmp0(cpin, "READY") != 0) {
+ if (state != OFONO_SIM_STATE_INSERTED) {
+ ofono_info("%s: sim locked", path);
+ ofono_sim_inserted_notify(data->sim, true);
+ }
+
+ return;
+ }
+
+ g_at_chat_unregister(data->aux, data->sim_watch);
+ data->sim_watch = 0;
+
+ data->init_timeout = l_timeout_create_ms(500, init_timer_cb, modem,
NULL);
+ if (!data->init_timeout) {
+ close_serial(modem);
+ return;
+ }
+}
+
+static void cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct quectel_data *data = ofono_modem_get_data(modem);
+ struct ofono_error error;
+
+ if (ok)
+ return;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (error.type != OFONO_ERROR_TYPE_CME)
+ return;
+
+ switch (error.error) {
+ case 5:
+ case 6:
+ case 7:
+ case 11:
+ case 12:
+ case 17:
+ case 18:
ofono_sim_inserted_notify(data->sim, true);
break;
- default:
+ case 10:
+ ofono_warn("%s: sim not present", ofono_modem_get_path(modem));
+ break;
+ case 13:
+ case 14:
+ case 15:
+ /* wait for +CPIN: indication */
break;
+ default:
+ ofono_error("unknown cpin error: %i", error.error);
}
}
+static void quectel_pre_sim(struct ofono_modem *modem)
+{
+ struct quectel_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ ofono_voicecall_create(modem, data->vendor, "atmodem", data->aux);
+ data->sim = ofono_sim_create(modem, data->vendor, "atmodem", data->aux);
+ data->sim_watch = g_at_chat_register(data->aux, "+CPIN:", sim_watch_cb,
+ FALSE, modem, NULL);
+
+ /*
+ * unsolicited indications about a missing or locked sim can occur
before
+ * the auto-baud dance in open_serial(), so issue a CPIN query here
+ *
+ * the callback is only called for CME errors to catch those. The +CPIN
+ * response is catched by the watch registered above
+ */
+ g_at_chat_send(data->aux, "AT+CPIN?", none_prefix, cpin_cb, modem,
NULL);
+}
+
static void quectel_post_sim(struct ofono_modem *modem)
{
struct quectel_data *data = ofono_modem_get_data(modem);
@@ -1179,31 +1098,9 @@ static void quectel_post_sim(struct ofono_modem *modem)
if (gprs && gc)
ofono_gprs_add_context(gprs, gc);
- /*
- * the sim related atoms must not be created until the modem is really
- * ready, so check the state here
- */
- switch (data->state) {
- case QUECTEL_STATE_INITIALIZING:
- /*
- * the modem is still initializing, so postpone the atom
- * creation until qinistat_cb() determines the modem is
- * ready
- */
- data->state = QUECTEL_STATE_POST_SIM;
- return;
- case QUECTEL_STATE_READY:
- /* the modem is ready, so create atoms below */
- break;
- default:
- return;
- }
-
ofono_sms_create(modem, data->vendor, "atmodem", data->aux);
ofono_phonebook_create(modem, data->vendor, "atmodem", data->aux);
- ofono_voicecall_create(modem, data->vendor, "atmodem", data->aux);
ofono_call_volume_create(modem, data->vendor, "atmodem", data->aux);
- data->state = QUECTEL_STATE_INITIALIZED;
}
static void quectel_post_online(struct ofono_modem *modem)
--
2.23.0
_______________________________________________
ofono mailing list
[email protected]
https://lists.ofono.org/mailman/listinfo/ofono