diff options
-rw-r--r-- | src/mm-plugin-base.c | 55 | ||||
-rw-r--r-- | src/mm-serial-port.c | 29 | ||||
-rw-r--r-- | src/mm-serial-port.h | 3 |
3 files changed, 79 insertions, 8 deletions
diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index 202eaac9..4b74feb7 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -77,6 +77,8 @@ typedef enum { PROBE_STATE_LAST } ProbeState; +static void probe_complete (MMPluginBaseSupportsTask *task); + /*****************************************************************************/ G_DEFINE_TYPE (MMPluginBaseSupportsTask, mm_plugin_base_supports_task, G_TYPE_OBJECT) @@ -91,6 +93,7 @@ typedef struct { guint open_id; guint32 open_tries; + guint full_id; MMSerialPort *probe_port; guint32 probed_caps; @@ -198,6 +201,11 @@ mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task, priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); g_return_if_fail (priv->callback != NULL); + if (priv->full_id) { + g_source_remove (priv->full_id); + priv->full_id = 0; + } + subsys = g_udev_device_get_subsystem (priv->port); name = g_udev_device_get_name (priv->port); @@ -251,11 +259,15 @@ supports_task_dispose (GObject *object) if (priv->open_id) g_source_remove (priv->open_id); + if (priv->full_id) + g_source_remove (priv->full_id); if (priv->probe_id) g_source_remove (priv->probe_id); - if (priv->probe_port) + if (priv->probe_port) { + mm_serial_port_close (priv->probe_port); g_object_unref (priv->probe_port); + } G_OBJECT_CLASS (mm_plugin_base_supports_task_parent_class)->dispose (object); } @@ -349,6 +361,44 @@ parse_cgmm (const char *buf) return 0; } +static const char *dq_strings[] = { + "option/faema_", "os_logids.h", NULL +}; + +static void +port_buffer_full (MMSerialPort *port, GString *buffer, gpointer user_data) +{ + MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data); + MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (user_data); + const char **iter; + size_t iter_len; + int i; + + /* 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->str[i], *iter, iter_len)) { + /* Immediately close the port and complete probing */ + priv->probed_caps = 0; + mm_serial_port_close (priv->probe_port); + probe_complete (task); + return; + } + } + } +} + static gboolean emit_probe_result (gpointer user_data) { @@ -626,6 +676,9 @@ try_open (gpointer user_data) port = mm_plugin_base_supports_task_get_port (task); g_assert (port); + task_priv->full_id = g_signal_connect (task_priv->probe_port, "buffer-full", + G_CALLBACK (port_buffer_full), task); + g_debug ("(%s): probe requested by plugin '%s'", g_udev_device_get_name (port), mm_plugin_get_name (MM_PLUGIN (task_priv->plugin))); diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 1d98a537..2134751f 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -730,9 +730,13 @@ data_available (GIOChannel *source, status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err); if (status == G_IO_STATUS_ERROR) { - g_warning ("%s", err->message); - g_error_free (err); - err = NULL; + if (err && err->message) + g_warning ("%s", err->message); + g_clear_error (&err); + + /* Serial port is closed; we're done */ + if (priv->watch_id == 0) + break; } /* If no bytes read, just let g_io_channel wait for more data */ @@ -745,10 +749,10 @@ data_available (GIOChannel *source, } /* Make sure the string doesn't grow too long */ - if (priv->response->len > SERIAL_BUF_SIZE) { - g_warning ("%s (%s): response buffer filled before repsonse received", - G_STRFUNC, mm_port_get_device (MM_PORT (self))); - g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2)); + if (priv->response->len > SERIAL_BUF_SIZE) { + /* Notify listeners and then trim the buffer */ + g_signal_emit_by_name (self, "buffer-full", priv->response); + g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2)); } if (parse_response (self, priv->response, &err)) @@ -888,6 +892,7 @@ mm_serial_port_close (MMSerialPort *self) if (priv->channel) { g_source_remove (priv->watch_id); + priv->watch_id = 0; g_io_channel_shutdown (priv->channel, TRUE, NULL); g_io_channel_unref (priv->channel); priv->channel = NULL; @@ -1293,4 +1298,14 @@ mm_serial_port_class_init (MMSerialPortClass *klass) "Send delay", 0, G_MAXUINT64, 0, G_PARAM_READWRITE)); + + /* Signals */ + g_signal_new ("buffer-full", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMSerialPortClass, buffer_full), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); } + diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h index a2697f30..dd5a6689 100644 --- a/src/mm-serial-port.h +++ b/src/mm-serial-port.h @@ -62,6 +62,9 @@ struct _MMSerialPort { struct _MMSerialPortClass { MMPortClass parent; + + /* Signals */ + void (*buffer_full) (MMSerialPort *port, const GString *buffer); }; GType mm_serial_port_get_type (void); |