All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3 1/2] quectel: rework sim detection
@ 2019-10-07 21:39 Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-10-07 21:39 ` [PATCHv3 2/2] quectel: support own cmux implementation over kernel line discipline Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-10-11 17:12 ` [PATCHv3 1/2] quectel: rework sim detection Denis Kenzior
  0 siblings, 2 replies; 4+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-10-07 21:39 UTC (permalink / raw
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 12508 bytes --]

Use at_util_sim_state_query_new() to query the sim inserted state. Once
that returns, the locked state is queried by issuing a AT+CPIN? command.

If not locked, a timer is started to query the quectel init status of
the sim. Once the init status is ready, the sim atom is created, and the
modem is set to powered, and the sim is signaled both inserted, and
initialized.

If locked, the modem is set to powered, and the sim atom is created.
This allows users to enter the pin to unlock the sim. Once the sim is
unlocked, a +CPIN: READY indication is caught to query the quectel
init status. Once the init status is ready, the sim is signaled
initialized.

All the above is needed, because the modem indicated +CPIN: READY before
the sim is really ready. The only way to be certain, is to wait for the
quectel init status to be ready. Even signaling the sim inserted
prematurely can cause to modem to hang during the initial AT+CRSM
commands.
---

Changes since v2:
 * None

 plugins/quectel.c | 255 +++++++++++++++++-----------------------------
 1 file changed, 94 insertions(+), 161 deletions(-)

diff --git a/plugins/quectel.c b/plugins/quectel.c
index a0e435b5..f19065b2 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -84,22 +84,15 @@ 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;
+	struct at_util_sim_state_query *sim_state_query;
 	unsigned int sim_watch;
+	bool sim_locked;
+	bool sim_ready;
 
 	/* used by quectel uart driver */
 	GAtChat *uart;
@@ -195,6 +188,7 @@ static void quectel_remove(struct ofono_modem *modem)
 	ofono_modem_set_data(modem, NULL);
 	l_timeout_remove(data->init_timeout);
 	l_gpio_writer_free(data->gpio);
+	at_util_sim_state_query_free(data->sim_state_query);
 	g_at_chat_unref(data->aux);
 	g_at_chat_unref(data->modem);
 	g_at_chat_unref(data->uart);
@@ -238,6 +232,9 @@ static void close_serial(struct ofono_modem *modem)
 
 	DBG("%p", modem);
 
+	at_util_sim_state_query_free(data->sim_state_query);
+	data->sim_state_query = NULL;
+
 	g_at_chat_unref(data->aux);
 	data->aux = NULL;
 
@@ -534,6 +531,7 @@ static void dbus_hw_enable(struct ofono_modem *modem)
 static void qinistat_cb(gboolean ok, GAtResult *result, gpointer user_data)
 {
 	struct ofono_modem *modem = user_data;
+	struct ofono_sim *sim = ofono_modem_get_sim(modem);
 	struct quectel_data *data = ofono_modem_get_data(modem);
 	GAtResultIter iter;
 	int ready = 0;
@@ -574,42 +572,13 @@ static void qinistat_cb(gboolean ok, GAtResult *result, gpointer user_data)
 	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;
+	if (data->sim_locked) {
+		ofono_sim_initialized_notify(sim);
 		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;
+	data->sim_ready = true;
+	ofono_modem_set_powered(modem, TRUE);
 }
 
 static void init_timer_cb(struct l_timeout *timeout, void *user_data)
@@ -627,118 +596,94 @@ 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);
+	GAtResultIter iter;
+	const char *cpin;
 
 	DBG("%p", modem);
 
-	g_at_chat_unregister(data->aux, data->sim_watch);
-	data->sim_watch = 0;
+	g_at_result_iter_init(&iter, result);
 
-	data->init_timeout = l_timeout_create_ms(500, init_timer_cb, modem, NULL);
-	if (!data->init_timeout) {
-		close_serial(modem);
+	if (!g_at_result_iter_next(&iter, "+CPIN:"))
 		return;
-	}
-}
 
-static enum ofono_sim_state cme_parse(GAtResult *result)
-{
-	struct ofono_error error;
+	g_at_result_iter_next_unquoted_string(&iter, &cpin);
 
-	decode_at_error(&error, g_at_result_final_response(result));
+	if (g_strcmp0(cpin, "READY") != 0)
+		return;
 
-	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;
-	}
+	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);
 }
 
-static enum ofono_sim_state cpin_parse(GAtResult *result)
+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);
+	const char *path = ofono_modem_get_path(modem);
 	GAtResultIter iter;
 	const char *cpin;
 
+	DBG("%p", modem);
+
+	if (!ok) {
+		close_serial(modem);
+		return;
+	}
+
 	g_at_result_iter_init(&iter, result);
 
-	if (!g_at_result_iter_next(&iter, "+CPIN:"))
-		return OFONO_SIM_STATE_RESETTING;
+	if (!g_at_result_iter_next(&iter, "+CPIN:")) {
+		close_serial(modem);
+		return;
+	}
 
 	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) {
+		data->init_timeout = l_timeout_create_ms(500, init_timer_cb,
+								modem, NULL);
+		return;
+	}
 
-	if (g_strcmp0(cpin, "READY") == 0)
-		return OFONO_SIM_STATE_READY;
+	if (g_strcmp0(cpin, "SIM PIN") != 0) {
+		close_serial(modem);
+		return;
+	}
 
-	return OFONO_SIM_STATE_LOCKED_OUT;
+	ofono_info("%s: sim locked", path);
+	data->sim_locked = true;
+	data->sim_watch = g_at_chat_register(data->aux, "+CPIN:",
+						sim_watch_cb, FALSE,
+						modem, NULL);
+	ofono_modem_set_powered(modem, TRUE);
 }
 
-static void cpin_query(gboolean ok, GAtResult *result, gpointer user_data)
+static void sim_state_cb(gboolean present, gpointer user_data)
 {
 	struct ofono_modem *modem = user_data;
 	struct quectel_data *data = ofono_modem_get_data(modem);
+	const char *path = ofono_modem_get_path(modem);
 
-	DBG("%p ok %i", modem, ok);
+	DBG("%p present %d", modem, present);
 
-	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);
+	at_util_sim_state_query_free(data->sim_state_query);
+	data->sim_state_query = NULL;
+	data->sim_locked = false;
+	data->sim_ready = false;
+
+	if (!present) {
+		ofono_modem_set_powered(modem, TRUE);
+		ofono_warn("%s: sim not present", path);
+		return;
 	}
+
+	g_at_chat_send(data->aux, "AT+CPIN?", cpin_prefix, cpin_cb, modem,
+			NULL);
 }
 
-static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
+static void cfun_cb(gboolean ok, GAtResult *result, gpointer user_data)
 {
 	struct ofono_modem *modem = user_data;
 	struct quectel_data *data = ofono_modem_get_data(modem);
@@ -751,8 +696,24 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
 	}
 
 	dbus_hw_enable(modem);
+	data->sim_state_query = at_util_sim_state_query_new(data->aux,
+						2, 20, sim_state_cb, modem,
+						NULL);
+}
+
+static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	struct ofono_modem *modem = user_data;
+	struct quectel_data *data = ofono_modem_get_data(modem);
 
-	g_at_chat_send(data->aux, "AT+CPIN?", cpin_prefix, cpin_query, modem,
+	DBG("%p ok %d", modem, ok);
+
+	if (!ok) {
+		close_serial(modem);
+		return;
+	}
+
+	g_at_chat_send(data->aux, "AT+CFUN=4", none_prefix, cfun_cb, modem,
 			NULL);
 }
 
@@ -1108,8 +1069,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;
 }
 
@@ -1146,22 +1105,18 @@ static void quectel_set_online(struct ofono_modem *modem, ofono_bool_t online,
 static void quectel_pre_sim(struct ofono_modem *modem)
 {
 	struct quectel_data *data = ofono_modem_get_data(modem);
+	struct ofono_sim *sim;
 
 	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)
-		return;
+	ofono_voicecall_create(modem, data->vendor, "atmodem", data->aux);
+	sim = ofono_sim_create(modem, data->vendor, "atmodem", data->aux);
 
-	switch (data->sim_state) {
-	case OFONO_SIM_STATE_LOCKED_OUT:
-	case OFONO_SIM_STATE_READY:
-		ofono_sim_inserted_notify(data->sim, true);
-		break;
-	default:
-		break;
-	}
+	if (data->sim_locked || data->sim_ready)
+		ofono_sim_inserted_notify(sim, true);
+
+	if (data->sim_ready)
+		ofono_sim_initialized_notify(sim);
 }
 
 static void quectel_post_sim(struct ofono_modem *modem)
@@ -1179,31 +1134,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

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCHv3 2/2] quectel: support own cmux implementation over kernel line discipline
  2019-10-07 21:39 [PATCHv3 1/2] quectel: rework sim detection Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-10-07 21:39 ` Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-10-11 17:20   ` Denis Kenzior
  2019-10-11 17:12 ` [PATCHv3 1/2] quectel: rework sim detection Denis Kenzior
  1 sibling, 1 reply; 4+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-10-07 21:39 UTC (permalink / raw
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 10007 bytes --]

The in-kernel implementation of gsm0710 causes deadlocks in the
kernel[1], so switch the default back to the user-space implementation
in ofono.

The change also removes the timeout-callback used to defer disabling the
n_gsm line discipline, as that is no longer needed[2]

To enable use of the kernel line discipline, add an udev env entry with
OFONO_QUECTEL_MUX="n_gsm".

[1] https://lore.kernel.org/lkml/4b2455c0-25ba-0187-6df6-c63b4ccc6a6e(a)geanix.com/
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7030082a7415d18e3befdf1f9ec05b3d5de98de4
---

Changes since v2:
 * keep kernel line discipline support
 * remove unrelated check in quectel_disable()
 * remove unrelated setting of AT+IFC=0,0
 * revert to using at_util_open_device()

 plugins/quectel.c | 202 ++++++++++++++++++++++++++++++++++++----------
 plugins/udevng.c  |   5 ++
 2 files changed, 166 insertions(+), 41 deletions(-)

diff --git a/plugins/quectel.c b/plugins/quectel.c
index f19065b2..8b2c0133 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -36,6 +36,7 @@
 #include <ell/ell.h>
 #include <gatchat.h>
 #include <gattty.h>
+#include <gatmux.h>
 
 #define OFONO_API_SUBJECT_TO_CHANGE
 #include <ofono.h>
@@ -95,7 +96,9 @@ struct quectel_data {
 	bool sim_ready;
 
 	/* used by quectel uart driver */
+	GIOChannel *device;
 	GAtChat *uart;
+	GAtMux *mux;
 	int mux_ready_count;
 	int initial_ldisc;
 	struct l_gpio_writer *gpio;
@@ -192,43 +195,48 @@ static void quectel_remove(struct ofono_modem *modem)
 	g_at_chat_unref(data->aux);
 	g_at_chat_unref(data->modem);
 	g_at_chat_unref(data->uart);
+	g_at_mux_unref(data->mux);
+
+	if (data->device)
+		g_io_channel_unref(data->device);
+
 	l_free(data);
 }
 
-static void close_mux_cb(struct l_timeout *timeout, void *user_data)
+static void close_mux(struct ofono_modem *modem)
+{
+	struct quectel_data *data = ofono_modem_get_data(modem);
+
+	DBG("%p", modem);
+
+	g_io_channel_unref(data->device);
+	data->device = NULL;
+
+	g_at_mux_unref(data->mux);
+	data->mux = NULL;
+}
+
+static void close_ngsm(struct ofono_modem *modem)
 {
-	struct ofono_modem *modem = user_data;
 	struct quectel_data *data = ofono_modem_get_data(modem);
-	GIOChannel *device;
-	uint32_t gpio_value = 0;
-	ssize_t write_count;
 	int fd;
 
 	DBG("%p", modem);
 
-	device = g_at_chat_get_channel(data->uart);
-	fd = g_io_channel_unix_get_fd(device);
+	if (!data->device)
+		return;
+
+	fd = g_io_channel_unix_get_fd(data->device);
 
 	/* restore initial tty line discipline */
 	if (ioctl(fd, TIOCSETD, &data->initial_ldisc) < 0)
 		ofono_warn("Failed to restore line discipline");
-
-	/* terminate gsm 0710 multiplexing on the modem side */
-	write_count = write(fd, gsm0710_terminate, sizeof(gsm0710_terminate));
-	if (write_count != sizeof(gsm0710_terminate))
-		ofono_warn("Failed to terminate gsm multiplexing");
-
-	g_at_chat_unref(data->uart);
-	data->uart = NULL;
-
-	l_timeout_remove(timeout);
-	l_gpio_writer_set(data->gpio, 1, &gpio_value);
-	ofono_modem_set_powered(modem, FALSE);
 }
 
 static void close_serial(struct ofono_modem *modem)
 {
 	struct quectel_data *data = ofono_modem_get_data(modem);
+	uint32_t gpio_value = 0;
 
 	DBG("%p", modem);
 
@@ -241,19 +249,16 @@ static void close_serial(struct ofono_modem *modem)
 	g_at_chat_unref(data->modem);
 	data->modem = NULL;
 
-	/*
-	 * if gsm0710 multiplexing is used, the aux and modem file descriptors
-	 * must be closed before closing the underlying serial device to avoid
-	 * an old kernel dead-lock:
-	 * https://lists.ofono.org/pipermail/ofono/2011-March/009405.html
-	 *
-	 * setup a timer to iterate the mainloop once to let gatchat close the
-	 * virtual file descriptors unreferenced above
-	 */
-	if (data->uart)
-		l_timeout_create_ms(1, close_mux_cb, modem, NULL);
+	g_at_chat_unref(data->uart);
+	data->uart = NULL;
+
+	if (data->mux)
+		close_mux(modem);
 	else
-		ofono_modem_set_powered(modem, false);
+		close_ngsm(modem);
+
+	l_gpio_writer_set(data->gpio, 1, &gpio_value);
+	ofono_modem_set_powered(modem, FALSE);
 }
 
 static void dbus_hw_reply_properties(struct dbus_hw *hw)
@@ -793,6 +798,19 @@ static void cgmm_cb(int ok, GAtResult *result, void *user_data)
 			NULL);
 }
 
+static void setup_aux(struct ofono_modem *modem)
+{
+	struct quectel_data *data = ofono_modem_get_data(modem);
+
+	DBG("%p", modem);
+
+	g_at_chat_set_slave(data->modem, data->aux);
+	g_at_chat_send(data->aux, "ATE0; &C0; +CMEE=1; +QIURC=0", none_prefix,
+			NULL, NULL, NULL);
+	g_at_chat_send(data->aux, "AT+CGMM", cgmm_prefix, cgmm_cb, modem,
+			NULL);
+}
+
 static int open_ttys(struct ofono_modem *modem)
 {
 	struct quectel_data *data = ofono_modem_get_data(modem);
@@ -812,16 +830,73 @@ static int open_ttys(struct ofono_modem *modem)
 		return -EIO;
 	}
 
-	g_at_chat_set_slave(data->modem, data->aux);
-
-	g_at_chat_send(data->aux, "ATE0; &C0; +CMEE=1; +QIURC=0", none_prefix,
-			NULL, NULL, NULL);
-	g_at_chat_send(data->aux, "AT+CGMM", cgmm_prefix, cgmm_cb, modem,
-			NULL);
+	setup_aux(modem);
 
 	return -EINPROGRESS;
 }
 
+static GAtChat *create_chat(struct ofono_modem *modem, char *debug)
+{
+	struct quectel_data *data = ofono_modem_get_data(modem);
+	GIOChannel *channel;
+	GAtSyntax *syntax;
+	GAtChat *chat;
+
+	DBG("%p", modem);
+
+	channel = g_at_mux_create_channel(data->mux);
+	if (channel == NULL)
+		return NULL;
+
+	syntax = g_at_syntax_new_gsmv1();
+	chat = g_at_chat_new(channel, syntax);
+	g_at_syntax_unref(syntax);
+	g_io_channel_unref(channel);
+
+	if (chat == NULL)
+		return NULL;
+
+	if (getenv("OFONO_AT_DEBUG"))
+		g_at_chat_set_debug(chat, quectel_debug, debug);
+
+	return chat;
+}
+
+static void cmux_gatmux(struct ofono_modem *modem)
+{
+	struct quectel_data *data = ofono_modem_get_data(modem);
+
+	DBG("%p", modem);
+
+	data->mux = g_at_mux_new_gsm0710_basic(data->device, 127);
+	if (data->mux == NULL) {
+		ofono_error("failed to create gsm0710 mux");
+		close_serial(modem);
+		return;
+	}
+
+	if (getenv("OFONO_MUX_DEBUG"))
+		g_at_mux_set_debug(data->mux, quectel_debug, "Mux: ");
+
+	g_at_mux_start(data->mux);
+
+	data->modem = create_chat(modem, "Modem: ");
+	if (!data->modem) {
+		ofono_error("failed to create modem channel");
+		close_serial(modem);
+		return;
+	}
+
+	data->aux = create_chat(modem, "Aux: ");
+	if (!data->aux) {
+		ofono_error("failed to create aux channel");
+		close_serial(modem);
+		return;
+	}
+
+	setup_aux(modem);
+}
+
 static void mux_ready_cb(struct l_timeout *timeout, void *user_data)
 {
 	struct ofono_modem *modem = user_data;
@@ -854,9 +929,8 @@ static void mux_ready_cb(struct l_timeout *timeout, void *user_data)
 	g_at_chat_set_slave(data->uart, data->modem);
 }
 
-static void cmux_cb(gboolean ok, GAtResult *result, gpointer user_data)
+static void cmux_ngsm(struct ofono_modem *modem)
 {
-	struct ofono_modem *modem = user_data;
 	struct quectel_data *data = ofono_modem_get_data(modem);
 	struct gsm_config gsm_config;
 	GIOChannel *device;
@@ -865,8 +939,7 @@ static void cmux_cb(gboolean ok, GAtResult *result, gpointer user_data)
 
 	DBG("%p", modem);
 
-	device = g_at_chat_get_channel(data->uart);
-	fd = g_io_channel_unix_get_fd(device);
+	fd = g_io_channel_unix_get_fd(data->device);
 
 	/* get initial line discipline to restore after use */
 	if (ioctl(fd, TIOCGETD, &data->initial_ldisc) < 0) {
@@ -922,6 +995,39 @@ static void cmux_cb(gboolean ok, GAtResult *result, gpointer user_data)
 	}
 }
 
+static void cmux_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	struct ofono_modem *modem = user_data;
+	struct quectel_data *data = ofono_modem_get_data(modem);
+	const char *mux = ofono_modem_get_string(modem, "Mux");
+
+	DBG("%p", modem);
+
+	g_at_chat_unref(data->uart);
+	data->uart = NULL;
+
+	if (!ok) {
+		close_serial(modem);
+		return;
+	}
+
+	if (!mux)
+		mux = "internal";
+
+	if (strcmp(mux, "n_gsm") == 0) {
+		cmux_ngsm(modem);
+		return;
+	}
+
+	if (strcmp(mux, "internal") == 0) {
+		cmux_gatmux(modem);
+		return;
+	}
+
+	ofono_error("unsupported mux setting: '%s'", mux);
+	close_serial(modem);
+}
+
 static void ate_cb(int ok, GAtResult *result, void *user_data)
 {
 	struct ofono_modem *modem = user_data;
@@ -979,6 +1085,8 @@ static int open_serial(struct ofono_modem *modem)
 	struct quectel_data *data = ofono_modem_get_data(modem);
 	const uint32_t gpio_value = 1;
 	const char *rts_cts;
+	ssize_t written;
+	int fd;
 
 	DBG("%p", modem);
 
@@ -998,6 +1106,18 @@ static int open_serial(struct ofono_modem *modem)
 	if (data->uart == NULL)
 		return -EINVAL;
 
+	data->device = g_at_chat_get_channel(data->uart);
+	g_io_channel_ref(data->device);
+
+	/*
+	 * terminate gsm 0710 multiplexing on the modem side to make sure it
+	 * responds to plain AT commands
+	 * */
+	fd = g_io_channel_unix_get_fd(data->device);
+	written = write(fd, gsm0710_terminate, sizeof(gsm0710_terminate));
+	if (written != sizeof(gsm0710_terminate))
+		ofono_warn("Failed to terminate gsm multiplexing");
+
 	if (data->gpio && !l_gpio_writer_set(data->gpio, 1, &gpio_value)) {
 		close_serial(modem);
 		return -EIO;
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 40ed2b02..4a38621b 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -893,6 +893,11 @@ static gboolean setup_quectel_serial(struct modem_info *modem)
 	if (value)
 		ofono_modem_set_string(modem->modem, "GpioOffset", value);
 
+	value = udev_device_get_property_value(info->dev,
+						"OFONO_QUECTEL_MUX");
+	if (value)
+		ofono_modem_set_string(modem->modem, "Mux", value);
+
 	value = udev_device_get_property_value(info->dev,
 						"OFONO_QUECTEL_RTSCTS");
 	ofono_modem_set_string(modem->modem, "RtsCts", value ? value : "off");
-- 
2.23.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCHv3 1/2] quectel: rework sim detection
  2019-10-07 21:39 [PATCHv3 1/2] quectel: rework sim detection Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-10-07 21:39 ` [PATCHv3 2/2] quectel: support own cmux implementation over kernel line discipline Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-10-11 17:12 ` Denis Kenzior
  1 sibling, 0 replies; 4+ messages in thread
From: Denis Kenzior @ 2019-10-11 17:12 UTC (permalink / raw
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1146 bytes --]

Hi Martin,

On 10/7/19 4:39 PM, Martin Hundebøll wrote:
> Use at_util_sim_state_query_new() to query the sim inserted state. Once
> that returns, the locked state is queried by issuing a AT+CPIN? command.
> 
> If not locked, a timer is started to query the quectel init status of
> the sim. Once the init status is ready, the sim atom is created, and the
> modem is set to powered, and the sim is signaled both inserted, and
> initialized.
> 
> If locked, the modem is set to powered, and the sim atom is created.
> This allows users to enter the pin to unlock the sim. Once the sim is
> unlocked, a +CPIN: READY indication is caught to query the quectel
> init status. Once the init status is ready, the sim is signaled
> initialized.
> 
> All the above is needed, because the modem indicated +CPIN: READY before
> the sim is really ready. The only way to be certain, is to wait for the
> quectel init status to be ready. Even signaling the sim inserted
> prematurely can cause to modem to hang during the initial AT+CRSM
> commands.
> ---
> 
> Changes since v2:
>   * None
> 

Applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCHv3 2/2] quectel: support own cmux implementation over kernel line discipline
  2019-10-07 21:39 ` [PATCHv3 2/2] quectel: support own cmux implementation over kernel line discipline Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-10-11 17:20   ` Denis Kenzior
  0 siblings, 0 replies; 4+ messages in thread
From: Denis Kenzior @ 2019-10-11 17:20 UTC (permalink / raw
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1375 bytes --]

Hi Martin,

On 10/7/19 4:39 PM, Martin Hundebøll wrote:
> The in-kernel implementation of gsm0710 causes deadlocks in the
> kernel[1], so switch the default back to the user-space implementation
> in ofono.
> 
> The change also removes the timeout-callback used to defer disabling the
> n_gsm line discipline, as that is no longer needed[2]
> 
> To enable use of the kernel line discipline, add an udev env entry with
> OFONO_QUECTEL_MUX="n_gsm".
> 
> [1] https://lore.kernel.org/lkml/4b2455c0-25ba-0187-6df6-c63b4ccc6a6e(a)geanix.com/
> [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7030082a7415d18e3befdf1f9ec05b3d5de98de4
> ---
> 
> Changes since v2:
>   * keep kernel line discipline support
>   * remove unrelated check in quectel_disable()
>   * remove unrelated setting of AT+IFC=0,0
>   * revert to using at_util_open_device()
> 
>   plugins/quectel.c | 202 ++++++++++++++++++++++++++++++++++++----------
>   plugins/udevng.c  |   5 ++
>   2 files changed, 166 insertions(+), 41 deletions(-)
> 


I split this patch up into two and squashed this warning:

plugins/quectel.c:936:14: error: unused variable ‘device’ 
[-Werror=unused-variable]
   936 |  GIOChannel *device;
       |              ^~~~~~

by taking out the offending variable declaration.

Applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-10-11 17:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-10-07 21:39 [PATCHv3 1/2] quectel: rework sim detection Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-10-07 21:39 ` [PATCHv3 2/2] quectel: support own cmux implementation over kernel line discipline Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-10-11 17:20   ` Denis Kenzior
2019-10-11 17:12 ` [PATCHv3 1/2] quectel: rework sim detection Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.