aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniele Palmas <dnlplm@gmail.com>2020-09-29 16:03:55 +0200
committerDaniele Palmas <dnlplm@gmail.com>2020-10-05 21:49:44 +0200
commitf6c4e3369a29c1f1bf14325be5a362a3ba29a71c (patch)
tree4a9bddbc14d5125d83386de56b3873caf46f4503
parent71cd727425d66bb5f7854cde2d4c033e73cbba97 (diff)
telit: add initial delay for AT ports to become responsive
Add a polling mechanism for port responsiveness, since some modem families require some time before being usable after the serial ports have been exposed by the kernel.
-rw-r--r--plugins/telit/mm-common-telit.c82
1 files changed, 81 insertions, 1 deletions
diff --git a/plugins/telit/mm-common-telit.c b/plugins/telit/mm-common-telit.c
index 0493fd54..f53f5b75 100644
--- a/plugins/telit/mm-common-telit.c
+++ b/plugins/telit/mm-common-telit.c
@@ -17,6 +17,7 @@
#include "mm-common-telit.h"
#include "mm-log-object.h"
+#include "mm-serial-parsers.h"
/*****************************************************************************/
@@ -28,6 +29,11 @@
#define TELIT_GE910_FAMILY_PID 0x0022
+/* The following number of retries of the port responsiveness
+ * check allows having up to 30 seconds of wait, that should
+ * be fine for most of the modems */
+#define TELIT_PORT_CHECK_RETRIES 6
+
gboolean
telit_grab_port (MMPlugin *self,
MMBaseModem *modem,
@@ -88,6 +94,7 @@ typedef struct {
MMPortSerialAt *port;
gboolean getportcfg_done;
guint getportcfg_retries;
+ guint port_responsive_retries;
} TelitCustomInitContext;
gboolean
@@ -274,6 +281,67 @@ out:
g_object_unref (task);
}
+static void at_ready (MMPortSerialAt *port,
+ GAsyncResult *res,
+ GTask *task);
+
+static void
+wait_for_ready (GTask *task)
+{
+ TelitCustomInitContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+
+ if (ctx->port_responsive_retries == 0) {
+ telit_custom_init_step (task);
+ return;
+ }
+ ctx->port_responsive_retries--;
+
+ mm_port_serial_at_command (
+ ctx->port,
+ "AT",
+ 5,
+ FALSE, /* raw */
+ FALSE, /* allow_cached */
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)at_ready,
+ task);
+}
+
+static void
+at_ready (MMPortSerialAt *port,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMPortProbe *probe;
+ g_autoptr(GError) error = NULL;
+
+ probe = g_task_get_source_object (task);
+
+ mm_port_serial_at_command_finish (port, res, &error);
+ if (error) {
+ /* On a timeout or send error, wait */
+ if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT) ||
+ g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED)) {
+ wait_for_ready (task);
+ return;
+ }
+ /* On an unknown error, make it fatal */
+ if (!mm_serial_parser_v1_is_known_error (error)) {
+ mm_obj_warn (probe, "custom port initialization logic failed: %s", error->message);
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ /* When successful mark the port as AT and continue checking #PORTCFG */
+ mm_obj_dbg (probe, "port is AT");
+ mm_port_probe_set_result_at (probe, TRUE);
+ telit_custom_init_step (task);
+}
+
void
telit_custom_init (MMPortProbe *probe,
MMPortSerialAt *port,
@@ -283,15 +351,27 @@ telit_custom_init (MMPortProbe *probe,
{
TelitCustomInitContext *ctx;
GTask *task;
+ gboolean wait_needed;
ctx = g_slice_new (TelitCustomInitContext);
ctx->port = g_object_ref (port);
ctx->getportcfg_done = FALSE;
ctx->getportcfg_retries = 3;
-
+ ctx->port_responsive_retries = TELIT_PORT_CHECK_RETRIES;
task = g_task_new (probe, cancellable, callback, user_data);
g_task_set_check_cancellable (task, FALSE);
g_task_set_task_data (task, ctx, (GDestroyNotify)telit_custom_init_context_free);
+ /* Some Telit modems require an initial delay for the ports to be responsive
+ * If no explicit tag is present, the modem does not need this step
+ * and can directly look for #PORTCFG support */
+ wait_needed = mm_kernel_device_get_global_property_as_boolean (mm_port_probe_peek_port (probe),
+ "ID_MM_TELIT_PORT_DELAY");
+ if (wait_needed) {
+ mm_obj_dbg (probe, "Start polling for port responsiveness");
+ wait_for_ready (task);
+ return;
+ }
+
telit_custom_init_step (task);
}