From 8d42094608e68eccbcf5838d87fd59aa605a18be Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 16 Dec 2009 15:26:05 -0800 Subject: [PATCH] zte: handle unsolicited messages during probe This implements the same fixes that NetworkManager's 0.7 branch implemented in commits f38ad328acfdc6ce29dd1380602c546b064161ae and 1235f71b20c92cded4abd976ccc5010649aae1a0. Many ZTE devices will spam the port with messages about waiting voicemail/SMS which buffer up and cause the device to eventually crash if not suppressed. --- plugins/mm-plugin-zte.c | 9 +++++ src/mm-plugin-base.c | 76 ++++++++++++++++++++++++++++++++++++++++- src/mm-plugin-base.h | 5 +++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/plugins/mm-plugin-zte.c b/plugins/mm-plugin-zte.c index 60a40a97..101fb468 100644 --- a/plugins/mm-plugin-zte.c +++ b/plugins/mm-plugin-zte.c @@ -93,6 +93,15 @@ supports_port (MMPluginBase *base, } /* Otherwise kick off a probe */ + + /* Many ZTE devices will flood the port with "Message waiting" indications + * and eventually fill up the serial buffer and crash. We need to turn off + * that indicator. See NetworkManager commits + * 1235f71b20c92cded4abd976ccc5010649aae1a0 and + * f38ad328acfdc6ce29dd1380602c546b064161ae for more details. + */ + mm_plugin_base_supports_task_set_custom_init_command (task, "ATE0+CPMS?", 3, 4, TRUE); + if (mm_plugin_base_probe_port (base, task, NULL)) return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index ad849218..e6dc6cba 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -95,6 +95,12 @@ typedef struct { char *probe_resp; GError *probe_error; + char *custom_init; + guint32 custom_init_max_tries; + guint32 custom_init_tries; + guint32 custom_init_delay_seconds; + gboolean custom_init_fail_if_timeout; + MMSupportsPortResultFunc callback; gpointer callback_data; } MMPluginBaseSupportsTaskPrivate; @@ -198,6 +204,27 @@ mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task, priv->callback_data = NULL; } +void +mm_plugin_base_supports_task_set_custom_init_command (MMPluginBaseSupportsTask *task, + const char *cmd, + guint32 delay_seconds, + guint32 max_tries, + gboolean fail_if_timeout) +{ + MMPluginBaseSupportsTaskPrivate *priv; + + g_return_if_fail (task != NULL); + g_return_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task)); + + priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); + + g_free (priv->custom_init); + priv->custom_init = g_strdup (cmd); + priv->custom_init_max_tries = max_tries; + priv->custom_init_delay_seconds = delay_seconds; + priv->custom_init_fail_if_timeout = fail_if_timeout; +} + static void mm_plugin_base_supports_task_init (MMPluginBaseSupportsTask *self) { @@ -216,6 +243,7 @@ supports_task_dispose (GObject *object) g_free (priv->driver); g_free (priv->probe_resp); g_clear_error (&(priv->probe_error)); + g_free (priv->custom_init); if (priv->open_id) g_source_remove (priv->open_id); @@ -467,10 +495,56 @@ parse_response (MMSerialPort *port, task_priv->probe_id = g_idle_add (handle_probe_response, task); } +static void flash_done (MMSerialPort *port, GError *error, gpointer user_data); + +static void +custom_init_response (MMSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data); + MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); + + if (error) { + task_priv->custom_init_tries++; + if (task_priv->custom_init_tries < task_priv->custom_init_max_tries) { + /* Try the custom command again */ + flash_done (port, NULL, user_data); + return; + } else if (task_priv->custom_init_fail_if_timeout) { + /* Fail the probe if the plugin wanted it and the command timed out */ + if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_RESPONSE_TIMEOUT)) { + probe_complete (task); + return; + } + } + } + + /* Otherwise proceed to probing */ + mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data); +} + static void flash_done (MMSerialPort *port, GError *error, gpointer user_data) { - mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data); + MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data); + MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); + guint32 delay_secs = task_priv->custom_init_delay_seconds; + + /* Send the custom init command if any */ + if (task_priv->custom_init) { + if (!delay_secs) + delay_secs = 3; + mm_serial_port_queue_command (port, + task_priv->custom_init, + delay_secs, + custom_init_response, + user_data); + } else { + /* Otherwise start normal probing */ + custom_init_response (port, NULL, NULL, user_data); + } } static gboolean diff --git a/src/mm-plugin-base.h b/src/mm-plugin-base.h index 91d3ddba..49e68d47 100644 --- a/src/mm-plugin-base.h +++ b/src/mm-plugin-base.h @@ -68,6 +68,11 @@ guint32 mm_plugin_base_supports_task_get_probed_capabilities (MMPluginBaseSuppor void mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task, guint32 level); +void mm_plugin_base_supports_task_set_custom_init_command (MMPluginBaseSupportsTask *task, + const char *cmd, + guint32 delay_seconds, + guint32 max_tries, + gboolean fail_if_timeout); #define MM_TYPE_PLUGIN_BASE (mm_plugin_base_get_type ()) #define MM_PLUGIN_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_BASE, MMPluginBase))