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.
This commit is contained in:
@@ -39,6 +39,7 @@ mm_serial_error_get_type (void)
|
|||||||
ENUM_ENTRY (MM_SERIAL_OPEN_FAILED, "SerialOpenFailed"),
|
ENUM_ENTRY (MM_SERIAL_OPEN_FAILED, "SerialOpenFailed"),
|
||||||
ENUM_ENTRY (MM_SERIAL_SEND_FAILED, "SerialSendfailed"),
|
ENUM_ENTRY (MM_SERIAL_SEND_FAILED, "SerialSendfailed"),
|
||||||
ENUM_ENTRY (MM_SERIAL_RESPONSE_TIMEOUT, "SerialResponseTimeout"),
|
ENUM_ENTRY (MM_SERIAL_RESPONSE_TIMEOUT, "SerialResponseTimeout"),
|
||||||
|
ENUM_ENTRY (MM_SERIAL_OPEN_FAILED_NO_DEVICE, "SerialOpenFailedNoDevice"),
|
||||||
{ 0, 0, 0 }
|
{ 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -22,7 +22,8 @@
|
|||||||
enum {
|
enum {
|
||||||
MM_SERIAL_OPEN_FAILED = 0,
|
MM_SERIAL_OPEN_FAILED = 0,
|
||||||
MM_SERIAL_SEND_FAILED = 1,
|
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 ())
|
#define MM_SERIAL_ERROR (mm_serial_error_quark ())
|
||||||
|
@@ -85,6 +85,9 @@ typedef struct {
|
|||||||
GUdevDevice *physdev;
|
GUdevDevice *physdev;
|
||||||
char *driver;
|
char *driver;
|
||||||
|
|
||||||
|
guint open_id;
|
||||||
|
guint32 open_tries;
|
||||||
|
|
||||||
MMSerialPort *probe_port;
|
MMSerialPort *probe_port;
|
||||||
guint32 probed_caps;
|
guint32 probed_caps;
|
||||||
ProbeState probe_state;
|
ProbeState probe_state;
|
||||||
@@ -201,7 +204,7 @@ mm_plugin_base_supports_task_init (MMPluginBaseSupportsTask *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dispose (GObject *object)
|
supports_task_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (object);
|
MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (object);
|
||||||
|
|
||||||
@@ -214,6 +217,9 @@ dispose (GObject *object)
|
|||||||
g_free (priv->probe_resp);
|
g_free (priv->probe_resp);
|
||||||
g_clear_error (&(priv->probe_error));
|
g_clear_error (&(priv->probe_error));
|
||||||
|
|
||||||
|
if (priv->open_id)
|
||||||
|
g_source_remove (priv->open_id);
|
||||||
|
|
||||||
if (priv->probe_id)
|
if (priv->probe_id)
|
||||||
g_source_remove (priv->probe_id);
|
g_source_remove (priv->probe_id);
|
||||||
if (priv->probe_port)
|
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));
|
g_type_class_add_private (object_class, sizeof (MMPluginBaseSupportsTaskPrivate));
|
||||||
|
|
||||||
/* Virtual methods */
|
/* 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);
|
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
|
gboolean
|
||||||
mm_plugin_base_probe_port (MMPluginBase *self,
|
mm_plugin_base_probe_port (MMPluginBase *self,
|
||||||
MMPluginBaseSupportsTask *task,
|
MMPluginBaseSupportsTask *task,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
|
|
||||||
MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
|
MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
|
||||||
MMSerialPort *serial;
|
MMSerialPort *serial;
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -488,6 +534,12 @@ mm_plugin_base_probe_port (MMPluginBase *self,
|
|||||||
g_assert (name);
|
g_assert (name);
|
||||||
|
|
||||||
serial = mm_serial_port_new (name, MM_PORT_TYPE_PRIMARY);
|
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,
|
g_object_set (serial,
|
||||||
MM_SERIAL_PORT_SEND_DELAY, (guint64) 100000,
|
MM_SERIAL_PORT_SEND_DELAY, (guint64) 100000,
|
||||||
MM_PORT_CARRIER_DETECT, FALSE,
|
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_new (),
|
||||||
mm_serial_parser_v1_destroy);
|
mm_serial_parser_v1_destroy);
|
||||||
|
|
||||||
if (!mm_serial_port_open (serial, error)) {
|
/* Open the port */
|
||||||
g_object_unref (serial);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug ("(%s): probe requested by plugin '%s'", name, priv->name);
|
|
||||||
task_priv->probe_port = serial;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -791,11 +791,18 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
|
|||||||
|
|
||||||
g_message ("(%s) opening serial device...", device);
|
g_message ("(%s) opening serial device...", device);
|
||||||
devfile = g_strdup_printf ("/dev/%s", device);
|
devfile = g_strdup_printf ("/dev/%s", device);
|
||||||
|
errno = 0;
|
||||||
priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
|
priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
|
||||||
g_free (devfile);
|
g_free (devfile);
|
||||||
|
|
||||||
if (priv->fd < 0) {
|
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));
|
"Could not open serial device %s: %s", device, strerror (errno));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user