diff options
author | Dan Williams <dcbw@redhat.com> | 2009-11-26 13:54:47 -0800 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2009-11-26 13:54:47 -0800 |
commit | aea0be5b9a02926a1f8f72104ce32c7dabae3f84 (patch) | |
tree | 75c6790f50539e73576477318661221e43725005 /src | |
parent | 15595b33dc88724253a147b7894c953a5d3110e6 (diff) |
nozomi: fix detection (lp:425312)
Nozomi devices aren't quite ready when the ports show up, so
we have to keep trying to open the port for a few seconds and
eventually it'll succeed. Should really be fixed in the driver
(ie, don't create the ttys until they can actually be used) but
whatever.
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-errors.c | 1 | ||||
-rw-r--r-- | src/mm-errors.h | 3 | ||||
-rw-r--r-- | src/mm-plugin-base.c | 67 | ||||
-rw-r--r-- | src/mm-serial-port.c | 9 |
4 files changed, 68 insertions, 12 deletions
diff --git a/src/mm-errors.c b/src/mm-errors.c index 510fa6d0..6448b807 100644 --- a/src/mm-errors.c +++ b/src/mm-errors.c @@ -39,6 +39,7 @@ mm_serial_error_get_type (void) ENUM_ENTRY (MM_SERIAL_OPEN_FAILED, "SerialOpenFailed"), ENUM_ENTRY (MM_SERIAL_SEND_FAILED, "SerialSendfailed"), ENUM_ENTRY (MM_SERIAL_RESPONSE_TIMEOUT, "SerialResponseTimeout"), + ENUM_ENTRY (MM_SERIAL_OPEN_FAILED_NO_DEVICE, "SerialOpenFailedNoDevice"), { 0, 0, 0 } }; diff --git a/src/mm-errors.h b/src/mm-errors.h index bc43d3e9..4bf8ecad 100644 --- a/src/mm-errors.h +++ b/src/mm-errors.h @@ -22,7 +22,8 @@ enum { MM_SERIAL_OPEN_FAILED = 0, MM_SERIAL_SEND_FAILED = 1, - MM_SERIAL_RESPONSE_TIMEOUT = 2 + MM_SERIAL_RESPONSE_TIMEOUT = 2, + MM_SERIAL_OPEN_FAILED_NO_DEVICE = 3 }; #define MM_SERIAL_ERROR (mm_serial_error_quark ()) diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index 540670aa..ad849218 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -85,6 +85,9 @@ typedef struct { GUdevDevice *physdev; char *driver; + guint open_id; + guint32 open_tries; + MMSerialPort *probe_port; guint32 probed_caps; ProbeState probe_state; @@ -201,7 +204,7 @@ mm_plugin_base_supports_task_init (MMPluginBaseSupportsTask *self) } static void -dispose (GObject *object) +supports_task_dispose (GObject *object) { MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (object); @@ -214,6 +217,9 @@ dispose (GObject *object) g_free (priv->probe_resp); g_clear_error (&(priv->probe_error)); + if (priv->open_id) + g_source_remove (priv->open_id); + if (priv->probe_id) g_source_remove (priv->probe_id); if (priv->probe_port) @@ -230,7 +236,7 @@ mm_plugin_base_supports_task_class_init (MMPluginBaseSupportsTaskClass *klass) g_type_class_add_private (object_class, sizeof (MMPluginBaseSupportsTaskPrivate)); /* Virtual methods */ - object_class->dispose = dispose; + object_class->dispose = supports_task_dispose; } /*****************************************************************************/ @@ -467,12 +473,52 @@ flash_done (MMSerialPort *port, GError *error, gpointer user_data) mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data); } +static gboolean +try_open (gpointer user_data) +{ + MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data); + MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); + GError *error = NULL; + + task_priv->open_id = 0; + + if (!mm_serial_port_open (task_priv->probe_port, &error)) { + if (++task_priv->open_tries > 4) { + /* took too long to open the port; give up */ + g_warning ("(%s): failed to open after 4 tries.", + mm_port_get_device (MM_PORT (task_priv->probe_port))); + probe_complete (task); + } else if (g_error_matches (error, + MM_SERIAL_ERROR, + MM_SERIAL_OPEN_FAILED_NO_DEVICE)) { + /* this is nozomi being dumb; try again */ + task_priv->open_id = g_timeout_add_seconds (1, try_open, task); + } else { + /* some other hard error */ + probe_complete (task); + } + g_clear_error (&error); + } else { + /* success, start probing */ + GUdevDevice *port; + + port = mm_plugin_base_supports_task_get_port (task); + g_assert (port); + + g_debug ("(%s): probe requested by plugin '%s'", + g_udev_device_get_name (port), + mm_plugin_get_name (MM_PLUGIN (task_priv->plugin))); + mm_serial_port_flash (task_priv->probe_port, 100, flash_done, task); + } + + return FALSE; +} + gboolean mm_plugin_base_probe_port (MMPluginBase *self, MMPluginBaseSupportsTask *task, GError **error) { - MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self); MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); MMSerialPort *serial; const char *name; @@ -488,6 +534,12 @@ mm_plugin_base_probe_port (MMPluginBase *self, g_assert (name); serial = mm_serial_port_new (name, MM_PORT_TYPE_PRIMARY); + if (serial == NULL) { + g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Failed to create new serial port."); + return FALSE; + } + g_object_set (serial, MM_SERIAL_PORT_SEND_DELAY, (guint64) 100000, MM_PORT_CARRIER_DETECT, FALSE, @@ -498,14 +550,9 @@ mm_plugin_base_probe_port (MMPluginBase *self, mm_serial_parser_v1_new (), mm_serial_parser_v1_destroy); - if (!mm_serial_port_open (serial, error)) { - g_object_unref (serial); - return FALSE; - } - - g_debug ("(%s): probe requested by plugin '%s'", name, priv->name); + /* Open the port */ task_priv->probe_port = serial; - mm_serial_port_flash (serial, 100, flash_done, task); + task_priv->open_id = g_idle_add (try_open, task); return TRUE; } diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 250e00be..ad955008 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -791,11 +791,18 @@ mm_serial_port_open (MMSerialPort *self, GError **error) g_message ("(%s) opening serial device...", device); devfile = g_strdup_printf ("/dev/%s", device); + errno = 0; priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY); g_free (devfile); if (priv->fd < 0) { - g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED, + /* nozomi isn't ready yet when the port appears, and it'll return + * ENODEV when open(2) is called on it. Make sure we can handle this + * by returning a special error in that case. + */ + g_set_error (error, + MM_SERIAL_ERROR, + (errno == ENODEV) ? MM_SERIAL_OPEN_FAILED_NO_DEVICE : MM_SERIAL_OPEN_FAILED, "Could not open serial device %s: %s", device, strerror (errno)); return FALSE; } |