aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-plugin-base.c55
-rw-r--r--src/mm-serial-port.c29
-rw-r--r--src/mm-serial-port.h3
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);