diff options
author | Dan Williams <dan@ioncontrol.co> | 2024-10-08 09:06:42 -0500 |
---|---|---|
committer | Dan Williams <dan@ioncontrol.co> | 2025-03-27 18:40:38 -0500 |
commit | 7d75a897a85e94d2bd183b38f9248a40dee3a570 (patch) | |
tree | 138910d78dd8bf0512f5674df7633f52b89ea238 /src | |
parent | b04ca7939260b0167cb8d1466ec949fbf28dccaf (diff) |
port-probe: allow per-port ID_MM_TTY_AT_PROBE_TRIES tag for custom number of AT probes
For modems that need more time to respond to AT port probes (like some Telit devices,
and Cinterion-based Telit MV31/MV32) allow a custom number of AT probe tries on a
per-port basis for generic probing, or plugins that opt into this functionality.
Signed-off-by: Dan Williams <dan@ioncontrol.co>
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-port-probe-at.c | 5 | ||||
-rw-r--r-- | src/mm-port-probe.c | 189 | ||||
-rw-r--r-- | src/mm-port-probe.h | 11 | ||||
-rw-r--r-- | src/plugins/telit/77-mm-telit-port-types.rules | 24 |
4 files changed, 204 insertions, 25 deletions
diff --git a/src/mm-port-probe-at.c b/src/mm-port-probe-at.c index 37a5ab27..4505fc76 100644 --- a/src/mm-port-probe-at.c +++ b/src/mm-port-probe-at.c @@ -44,7 +44,10 @@ mm_port_probe_response_processor_is_at (const gchar *command, * they will just go on to the next command. */ if (g_error_matches (error, MM_SERIAL_ERROR, - MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) { + MM_SERIAL_ERROR_RESPONSE_TIMEOUT) || + g_error_matches (error, + MM_SERIAL_ERROR, + MM_SERIAL_ERROR_SEND_FAILED)) { return FALSE; } diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c index 45ffdde8..c01cbddb 100644 --- a/src/mm-port-probe.c +++ b/src/mm-port-probe.c @@ -120,6 +120,162 @@ static const MMStringUintMap port_subsys_map[] = { /*****************************************************************************/ +static const MMPortProbeAtCommand at_probing[] = { + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { "AT", 3, mm_port_probe_response_processor_is_at }, + { NULL } +}; + +typedef struct { + MMPortSerialAt *serial; + const MMPortProbeAtCommand *at_commands; + guint at_commands_limit; +} EarlyAtProbeContext; + +static void +early_at_probe_context_free (EarlyAtProbeContext *ctx) +{ + g_clear_object (&ctx->serial); + g_slice_free (EarlyAtProbeContext, ctx); +} + +gboolean +mm_port_probe_run_early_at_probe_finish (MMPortProbe *self, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); +} + +static void +early_at_probe_parse_response (MMPortSerialAt *serial, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(GVariant) result = NULL; + g_autoptr(GError) result_error = NULL; + g_autofree gchar *response = NULL; + g_autoptr(GError) command_error = NULL; + EarlyAtProbeContext *ctx; + MMPortProbe *self; + gboolean is_at = FALSE; + + ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + + /* If already cancelled, do nothing else */ + if (g_task_return_error_if_cancelled (task)) { + g_object_unref (task); + return; + } + + response = mm_port_serial_at_command_finish (serial, res, &command_error); + if (!ctx->at_commands->response_processor (ctx->at_commands->command, + response, + !!ctx->at_commands[1].command, + command_error, + &result, + &result_error)) { + /* Were we told to abort the whole probing? */ + if (result_error) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_UNSUPPORTED, + "(%s/%s) error while probing AT features: %s", + mm_kernel_device_get_subsystem (self->priv->port), + mm_kernel_device_get_name (self->priv->port), + result_error->message); + g_object_unref (task); + return; + } + + /* Go on to next command */ + ctx->at_commands++; + ctx->at_commands_limit--; + if (ctx->at_commands->command && ctx->at_commands_limit > 0) { + /* More commands in the group? */ + mm_port_serial_at_command ( + ctx->serial, + ctx->at_commands->command, + ctx->at_commands->timeout, + FALSE, /* raw */ + FALSE, /* allow_cached */ + g_task_get_cancellable (task), + (GAsyncReadyCallback)early_at_probe_parse_response, + task); + return; + } + + /* No more commands in the group; end probing; not AT */ + } else if (result) { + /* If any result given, it must be a boolean */ + g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE_BOOLEAN)); + is_at = g_variant_get_boolean (result); + } + + mm_port_probe_set_result_at (self, is_at); + g_task_return_boolean (task, is_at); + g_object_unref (task); +} + +gboolean +mm_port_probe_run_early_at_probe (MMPortProbe *self, + MMPortSerialAt *serial, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + EarlyAtProbeContext *ctx; + gint tries; + + tries = mm_kernel_device_get_global_property_as_int (mm_port_probe_peek_port (self), + ID_MM_TTY_AT_PROBE_TRIES); + if (tries == 0) { + /* Early probing not required */ + return FALSE; + } + + task = g_task_new (self, cancellable, callback, user_data); + + ctx = g_slice_new0 (EarlyAtProbeContext); + ctx->serial = g_object_ref (serial); + ctx->at_commands = at_probing; + ctx->at_commands_limit = CLAMP (tries, 1, (gint) G_N_ELEMENTS (at_probing)); + g_task_set_task_data (task, ctx, (GDestroyNotify) early_at_probe_context_free); + + mm_port_serial_at_command ( + ctx->serial, + ctx->at_commands->command, + ctx->at_commands->timeout, + FALSE, /* raw */ + FALSE, /* allow_cached */ + g_task_get_cancellable (task), + (GAsyncReadyCallback)early_at_probe_parse_response, + task); + return TRUE; +} + +/*****************************************************************************/ + static void mm_port_probe_clear (MMPortProbe *self) { @@ -420,6 +576,8 @@ typedef struct { const MMPortProbeAtCommand *at_custom_probe; /* Current group of AT commands to be sent */ const MMPortProbeAtCommand *at_commands; + /* Maximum number of at_commands to be sent */ + guint at_commands_limit; /* Seconds between each AT command sent in the group */ guint at_commands_wait_secs; /* Current AT Result processor */ @@ -1071,7 +1229,8 @@ probe_at_parse_response (MMPortSerialAt *port, /* Go on to next command */ ctx->at_commands++; - if (!ctx->at_commands->command) { + ctx->at_commands_limit--; + if (!ctx->at_commands->command || ctx->at_commands_limit == 0) { /* Was it the last command in the group? If so, * end this partial probing */ ctx->at_result_processor (self, NULL); @@ -1129,16 +1288,6 @@ probe_at (MMPortProbe *self) return G_SOURCE_REMOVE; } -static const MMPortProbeAtCommand at_probing[] = { - { "AT", 3, mm_port_probe_response_processor_is_at }, - { "AT", 3, mm_port_probe_response_processor_is_at }, - { "AT", 3, mm_port_probe_response_processor_is_at }, - { "AT", 3, mm_port_probe_response_processor_is_at }, - { "AT", 3, mm_port_probe_response_processor_is_at }, - { "AT", 3, mm_port_probe_response_processor_is_at }, - { NULL } -}; - static const MMPortProbeAtCommand vendor_probing[] = { { "+CGMI", 3, mm_port_probe_response_processor_string }, { "+GMI", 3, mm_port_probe_response_processor_string }, @@ -1339,6 +1488,8 @@ serial_open_at (MMPortProbe *self) MM_PORT_PROBE_AT_ICERA | \ MM_PORT_PROBE_AT_XMM) +#define AT_PROBING_DEFAULT_TRIES 6 + static void probe_step (MMPortProbe *self) { @@ -1355,6 +1506,7 @@ probe_step (MMPortProbe *self) ctx->at_result_processor = NULL; ctx->at_commands = NULL; ctx->at_commands_wait_secs = 0; + ctx->at_commands_limit = G_MAXUINT; /* run all given AT probes */ switch (ctx->step) { case PROBE_STEP_FIRST: @@ -1411,7 +1563,20 @@ probe_step (MMPortProbe *self) if ((ctx->flags & MM_PORT_PROBE_AT) && !(self->priv->flags & MM_PORT_PROBE_AT)) { mm_obj_msg (self, "probe step: AT"); /* Prepare AT probing */ - ctx->at_commands = ctx->at_custom_probe ? ctx->at_custom_probe : at_probing; + if (ctx->at_custom_probe) + ctx->at_commands = ctx->at_custom_probe; + else { + gint at_probe_tries; + + /* NOTE: update ID_MM_TTY_AT_PROBE_TRIES documentation when changing min/max/default */ + at_probe_tries = mm_kernel_device_get_property_as_int (mm_port_probe_peek_port (self), + ID_MM_TTY_AT_PROBE_TRIES); + /* If no tag, use default number of tries */ + if (at_probe_tries <= 0) + at_probe_tries = AT_PROBING_DEFAULT_TRIES; + ctx->at_commands_limit = MIN (at_probe_tries, (gint) G_N_ELEMENTS (at_probing)); + ctx->at_commands = at_probing; + } ctx->at_result_processor = probe_at_result_processor; ctx->source_id = g_idle_add ((GSourceFunc) probe_at, self); return; diff --git a/src/mm-port-probe.h b/src/mm-port-probe.h index fd427575..000b40da 100644 --- a/src/mm-port-probe.h +++ b/src/mm-port-probe.h @@ -128,6 +128,17 @@ gboolean mm_port_probe_run_finish (MMPortProbe *self, gboolean mm_port_probe_run_cancel_at_probing (MMPortProbe *self); +/* Run early AT probes from plugin custom init hooks */ +gboolean mm_port_probe_run_early_at_probe (MMPortProbe *self, + MMPortSerialAt *serial, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean mm_port_probe_run_early_at_probe_finish (MMPortProbe *self, + GAsyncResult *result, + GError **error); + /* Probing result getters */ MMPortType mm_port_probe_get_port_type (MMPortProbe *self); gboolean mm_port_probe_is_at (MMPortProbe *self); diff --git a/src/plugins/telit/77-mm-telit-port-types.rules b/src/plugins/telit/77-mm-telit-port-types.rules index 8a5849f7..48b40f4a 100644 --- a/src/plugins/telit/77-mm-telit-port-types.rules +++ b/src/plugins/telit/77-mm-telit-port-types.rules @@ -149,26 +149,26 @@ ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="7011", ENV{.MM_USBIFNUM}=="03", SUBS ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="7011", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1" # LM940/960 initial port delay -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1040", ENV{ID_MM_TELIT_PORT_DELAY}="1" -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1041", ENV{ID_MM_TELIT_PORT_DELAY}="1" -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1042", ENV{ID_MM_TELIT_PORT_DELAY}="1" -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1043", ENV{ID_MM_TELIT_PORT_DELAY}="1" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1040", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1041", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1042", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1043", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" # FN980 initial port delay -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1050", ENV{ID_MM_TELIT_PORT_DELAY}="1" -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1051", ENV{ID_MM_TELIT_PORT_DELAY}="1" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1050", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1051", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" # LN920 initial port delay -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1060", ENV{ID_MM_TELIT_PORT_DELAY}="1" -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1061", ENV{ID_MM_TELIT_PORT_DELAY}="1" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1060", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1061", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" # FN990 initial port delay -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1070", ENV{ID_MM_TELIT_PORT_DELAY}="1" -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1071", ENV{ID_MM_TELIT_PORT_DELAY}="1" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1070", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1071", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" # FN912C04 initial port delay -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="3000", ENV{ID_MM_TELIT_PORT_DELAY}="1" -ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="3001", ENV{ID_MM_TELIT_PORT_DELAY}="1" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="3000", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" +ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="3001", ENV{ID_MM_TTY_AT_PROBE_TRIES}="14" GOTO="mm_telit_end" |