summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2012-11-27 09:53:29 -0600
committerDan Williams <dcbw@redhat.com>2012-11-27 09:56:25 -0600
commitc90e41fb1327ad48166b58a8f8281ac6462a9690 (patch)
tree21744b9d0409dbe19028e8361c59aacbb1f4918b
parenta01e8aa31724ee1210b86d1d7261897a305d8710 (diff)
port-probe: early-exit if port is certainly not AT capable
If we read a response that indicates the port is definitely not an AT capable port, stop AT probing. Certain ports that use proprietary protocols or other non-AT protocols tend to spew data at us, so when this happens we can cut probing short.
-rw-r--r--src/mm-port-probe.c131
1 files changed, 74 insertions, 57 deletions
diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c
index 598ceb6e..263b6c42 100644
--- a/src/mm-port-probe.c
+++ b/src/mm-port-probe.c
@@ -347,12 +347,15 @@ port_probe_run_is_cancelled (MMPortProbe *self)
return TRUE;
}
return FALSE;
}
+/***************************************************************/
+/* QMI */
+
#if defined WITH_QMI
static void
qmi_port_open_ready (MMQmiPort *qmi_port,
GAsyncResult *res,
MMPortProbe *self)
@@ -408,12 +411,15 @@ wdm_probe_qmi (MMPortProbe *self)
port_probe_run_task_complete (task, TRUE, NULL);
#endif /* WITH_QMI */
return FALSE;
}
+/***************************************************************/
+/* QCDM */
+
static void
serial_probe_qcdm_parse_response (MMQcdmSerialPort *port,
GByteArray *response,
GError *error,
MMPortProbe *self)
{
@@ -564,12 +570,65 @@ serial_probe_qcdm (MMPortProbe *self)
(MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response,
self);
return FALSE;
}
+/***************************************************************/
+/* AT */
+
+static const gchar *non_at_strings[] = {
+ /* Option Icera-based devices */
+ "option/faema_",
+ "os_logids.h",
+ /* Sierra CnS port */
+ "NETWORK SERVICE CHANGE",
+ "/SRC/AMSS",
+ NULL
+};
+
+static const guint8 zerobuf[32] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static gboolean
+is_non_at_response (const guint8 *data, gsize len)
+{
+ const gchar **iter;
+ size_t iter_len;
+ int i;
+
+ /* Some devices (observed on a ZTE branded "QUALCOMM INCORPORATED" model
+ * "154") spew NULLs from some ports.
+ */
+ if ( (len >= sizeof (zerobuf))
+ && (memcmp (data, zerobuf, sizeof (zerobuf)) == 0))
+ return TRUE;
+
+ /* Check for a well-known non-AT response. There are some ports (eg many
+ * Icera-based chipsets, Qualcomm Gobi devices before their firmware is
+ * loaded, Sierra CnS ports) that just shouldn't be probed for AT capability
+ * if we get a certain response since that response means they aren't AT
+ * ports. Also, kernel bugs (at least with 2.6.31 and 2.6.32) trigger port
+ * flow control kernel oopses if we read too much data for these ports.
+ */
+ for (iter = &non_at_strings[0]; iter && *iter; iter++) {
+ /* Search in the response for the item; the response could have embedded
+ * nulls so we can't use memcmp() or strstr() on the whole response.
+ */
+ iter_len = strlen (*iter);
+ for (i = 0; (len >= iter_len) && (i < len - iter_len); i++) {
+ if (!memcmp (&data[i], *iter, iter_len))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static void
serial_probe_at_icera_result_processor (MMPortProbe *self,
GVariant *result)
{
if (result) {
/* If any result given, it must be a string */
@@ -651,12 +710,22 @@ serial_probe_at_parse_response (MMAtSerialPort *port,
g_udev_device_get_name (self->priv->port));
task->at_result_processor (self, NULL);
serial_probe_schedule (self);
return;
}
+ /* Early-abort AT probing if we get a response that indicates this is
+ * certainly not an AT-capable port.
+ */
+ if (response && is_non_at_response ((const guint8 *) response->str, response->len)) {
+ task->at_result_processor (self, NULL);
+ mm_port_probe_set_result_at (self, FALSE);
+ serial_probe_schedule (self);
+ return;
+ }
+
if (!task->at_commands->response_processor (task->at_commands->command,
response ? response->str : NULL,
!!task->at_commands[1].command,
error,
&result,
&result_error)) {
@@ -774,12 +843,14 @@ at_custom_init_ready (MMPortProbe *self,
/* Keep on with remaining probings */
task->at_custom_init_run = TRUE;
serial_probe_schedule (self);
}
+/***************************************************************/
+
static void
serial_probe_schedule (MMPortProbe *self)
{
PortProbeRunTask *task = self->priv->task;
/* If already cancelled, do nothing else */
@@ -859,75 +930,21 @@ serial_flash_done (MMSerialPort *port,
MMPortProbe *self)
{
/* Schedule probing */
serial_probe_schedule (self);
}
-static const gchar *dq_strings[] = {
- /* Option Icera-based devices */
- "option/faema_",
- "os_logids.h",
- /* Sierra CnS port */
- "NETWORK SERVICE CHANGE",
- "/SRC/AMSS",
- NULL
-};
-
-static const guint8 zerobuf[32] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
static void
serial_buffer_full (MMSerialPort *serial,
GByteArray *buffer,
MMPortProbe *self)
{
- const gchar **iter;
- size_t iter_len;
- int i;
-
- /* Some devices (observed on a ZTE branded "QUALCOMM INCORPORATED" model
- * "154") spew NULLs from some ports.
- */
- if ( (buffer->len >= sizeof (zerobuf))
- && (memcmp (buffer->data, zerobuf, sizeof (zerobuf)) == 0)) {
+ if (is_non_at_response (buffer->data, buffer->len)) {
mm_serial_port_close (serial);
- port_probe_run_task_complete (self->priv->task,
- FALSE,
- g_error_new_literal (MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Probing stopped due to non-AT response"));
- return;
- }
-
- /* Check for an immediate disqualification response. There are some
- * ports (Option Icera-based chipsets have them, as do Qualcomm Gobi
- * devices before their firmware is loaded) that just shouldn't be
- * probed if we get a certain response because we know they can't be
- * used. Kernel bugs (at least with 2.6.31 and 2.6.32) also trigger port
- * flow control kernel oopses if we read too much data for these ports.
- */
-
- for (iter = &dq_strings[0]; iter && *iter; iter++) {
- /* Search in the response for the item; the response could have embedded
- * nulls so we can't use memcmp() or strstr() on the whole response.
- */
- iter_len = strlen (*iter);
- for (i = 0; i < buffer->len - iter_len; i++) {
- if (!memcmp (&buffer->data[i], *iter, iter_len)) {
- /* Immediately close the port and complete probing */
- mm_serial_port_close (serial);
- port_probe_run_task_complete (self->priv->task,
- FALSE,
- g_error_new_literal (MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Probing stopped due to non-AT response"));
- return;
- }
- }
+ mm_port_probe_set_result_at (self, FALSE);
+ serial_probe_schedule (self);
}
}
static gboolean
serial_open_at (MMPortProbe *self)
{