aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2013-02-20 12:15:19 +0100
committerAleksander Morgado <aleksander@lanedo.com>2013-02-20 15:54:54 +0100
commit000bb642255ecfefe10f7b6629493c34877399c7 (patch)
tree1092294d763744a3512fc51e05871a047a37043f
parent9a6fce0a086f28aafda7d963e8661e98a4d44ef6 (diff)
serial-port: allow specifying some wait time between closing and reopening
We will now by default wait some time (1s) between port getting fully closed and the port being reopened again. This logic seems to work for multiple modems where there is a single port for both AT and data, like my Nokia C7 and Iridium modems. If this wait time is not applied, the port ends up returning EAGAIN for every write that we try to do afterwards.
-rw-r--r--src/mm-broadband-bearer.c75
-rw-r--r--src/mm-serial-port.c97
-rw-r--r--src/mm-serial-port.h8
3 files changed, 142 insertions, 38 deletions
diff --git a/src/mm-broadband-bearer.c b/src/mm-broadband-bearer.c
index eeaebd07..2e4be249 100644
--- a/src/mm-broadband-bearer.c
+++ b/src/mm-broadband-bearer.c
@@ -1295,6 +1295,27 @@ data_flash_cdma_ready (MMSerialPort *data,
}
static void
+data_reopen_cdma_ready (MMSerialPort *data,
+ GError *error,
+ DetailedDisconnectContext *ctx)
+{
+ if (error) {
+ /* Fatal */
+ g_simple_async_result_set_from_error (ctx->result, error);
+ detailed_disconnect_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Just flash the data port */
+ mm_dbg ("Flashing data port (%s)...", mm_port_get_device (MM_PORT (ctx->data)));
+ mm_serial_port_flash (MM_SERIAL_PORT (ctx->data),
+ 1000,
+ TRUE,
+ (MMSerialFlashFn)data_flash_cdma_ready,
+ ctx);
+}
+
+static void
disconnect_cdma (MMBroadbandBearer *self,
MMBroadbandModem *modem,
MMAtSerialPort *primary,
@@ -1304,7 +1325,6 @@ disconnect_cdma (MMBroadbandBearer *self,
gpointer user_data)
{
DetailedDisconnectContext *ctx;
- GError *error = NULL;
g_assert (primary != NULL);
@@ -1320,18 +1340,11 @@ disconnect_cdma (MMBroadbandBearer *self,
user_data);
/* Fully reopen the port before flashing */
- mm_dbg ("Reopening primary port...");
- if (!mm_serial_port_reopen (MM_SERIAL_PORT (ctx->primary), &error)) {
- mm_warn ("Disconnecting CDMA: %s", error->message);
- g_error_free (error);
- }
-
- /* Just flash the data port */
- mm_serial_port_flash (MM_SERIAL_PORT (ctx->data),
- 1000,
- TRUE,
- (MMSerialFlashFn)data_flash_cdma_ready,
- ctx);
+ mm_dbg ("Reopening data port (%s)...", mm_port_get_device (MM_PORT (ctx->data)));
+ mm_serial_port_reopen (MM_SERIAL_PORT (ctx->data),
+ 1000,
+ (MMSerialReopenFn)data_reopen_cdma_ready,
+ ctx);
}
/*****************************************************************************/
@@ -1410,18 +1423,19 @@ data_flash_3gpp_ready (MMSerialPort *data,
}
static void
-data_flash_3gpp (DetailedDisconnectContext *ctx)
+data_reopen_3gpp_ready (MMSerialPort *data,
+ GError *error,
+ DetailedDisconnectContext *ctx)
{
- GError *error = NULL;
-
- /* Fully reopen the port before flashing */
- mm_dbg ("Reopening data port...");
- if (!mm_serial_port_reopen (MM_SERIAL_PORT (ctx->data), &error)) {
- mm_warn ("Disconnecting 3GPP: %s", error->message);
- g_error_free (error);
+ if (error) {
+ /* Fatal */
+ g_simple_async_result_set_from_error (ctx->result, error);
+ detailed_disconnect_context_complete_and_free (ctx);
+ return;
}
- mm_dbg ("Flash data port...");
+ /* Just flash the data port */
+ mm_dbg ("Flashing data port (%s)...", mm_port_get_device (MM_PORT (ctx->data)));
mm_serial_port_flash (MM_SERIAL_PORT (ctx->data),
1000,
TRUE,
@@ -1430,6 +1444,17 @@ data_flash_3gpp (DetailedDisconnectContext *ctx)
}
static void
+data_reopen_3gpp (DetailedDisconnectContext *ctx)
+{
+ /* Fully reopen the port before flashing */
+ mm_dbg ("Reopening data port (%s)...", mm_port_get_device (MM_PORT (ctx->data)));
+ mm_serial_port_reopen (MM_SERIAL_PORT (ctx->data),
+ 1000,
+ (MMSerialReopenFn)data_reopen_3gpp_ready,
+ ctx);
+}
+
+static void
cgact_ready (MMBaseModem *modem,
GAsyncResult *res,
DetailedDisconnectContext *ctx)
@@ -1444,7 +1469,7 @@ cgact_ready (MMBaseModem *modem,
g_error_free (error);
}
- data_flash_3gpp (ctx);
+ data_reopen_3gpp (ctx);
}
static void
@@ -1512,8 +1537,8 @@ disconnect_3gpp (MMBroadbandBearer *self,
return;
}
- /* If no secondary port, go on to flash the data/primary port */
- data_flash_3gpp (ctx);
+ /* If no secondary port, go on to reopen & flash the data/primary port */
+ data_reopen_3gpp (ctx);
}
/*****************************************************************************/
diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c
index 2eab4a94..57820c14 100644
--- a/src/mm-serial-port.c
+++ b/src/mm-serial-port.c
@@ -98,6 +98,7 @@ typedef struct {
guint n_consecutive_timeouts;
guint flash_id;
+ guint reopen_id;
guint connected_id;
} MMSerialPortPrivate;
@@ -871,9 +872,17 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
priv = MM_SERIAL_PORT_GET_PRIVATE (self);
-
device = mm_port_get_device (MM_PORT (self));
+ if (priv->reopen_id) {
+ g_set_error (error,
+ MM_SERIAL_ERROR,
+ MM_SERIAL_ERROR_OPEN_FAILED,
+ "Could not open serial device %s: reopen operation in progress",
+ device);
+ return FALSE;
+ }
+
if (priv->open_count) {
/* Already open */
goto success;
@@ -1204,32 +1213,95 @@ mm_serial_port_queue_command_cached (MMSerialPort *self,
internal_queue_command (self, command, take_command, TRUE, timeout_seconds, cancellable, callback, user_data);
}
+typedef struct {
+ MMSerialPort *port;
+ guint initial_open_count;
+ MMSerialReopenFn callback;
+ gpointer user_data;
+} ReopenInfo;
+
+static void
+serial_port_reopen_cancel (MMSerialPort *self)
+{
+ MMSerialPortPrivate *priv;
+
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
+
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ if (priv->reopen_id > 0) {
+ g_source_remove (priv->reopen_id);
+ priv->reopen_id = 0;
+ }
+}
+
+static gboolean
+reopen_do (gpointer data)
+{
+ ReopenInfo *info = (ReopenInfo *) data;
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (info->port);
+ GError *error = NULL;
+ guint i;
+
+ priv->reopen_id = 0;
+
+ for (i = 0; i < info->initial_open_count; i++) {
+ if (!mm_serial_port_open (info->port, &error)) {
+ g_prefix_error (&error, "Couldn't reopen port (%u): ", i);
+ break;
+ }
+ }
+
+ info->callback (info->port, error, info->user_data);
+ if (error)
+ g_error_free (error);
+ g_slice_free (ReopenInfo, info);
+ return FALSE;
+}
+
gboolean
mm_serial_port_reopen (MMSerialPort *self,
- GError **error)
+ guint32 reopen_time,
+ MMSerialReopenFn callback,
+ gpointer user_data)
{
+ ReopenInfo *info;
MMSerialPortPrivate *priv;
- guint initial_open_count;
guint i;
g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ if (priv->reopen_id > 0) {
+ GError *error;
+
+ error = g_error_new_literal (MM_CORE_ERROR,
+ MM_CORE_ERROR_IN_PROGRESS,
+ "Modem is already being reopened.");
+ callback (self, error, user_data);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ info = g_slice_new0 (ReopenInfo);
+ info->port = self;
+ info->callback = callback;
+ info->user_data = user_data;
priv = MM_SERIAL_PORT_GET_PRIVATE (self);
- initial_open_count = priv->open_count;
+ info->initial_open_count = priv->open_count;
mm_dbg ("(%s) reopening port (%u)",
mm_port_get_device (MM_PORT (self)),
- initial_open_count);
+ info->initial_open_count);
- for (i = 0; i < initial_open_count; i++)
+ for (i = 0; i < info->initial_open_count; i++)
mm_serial_port_close (self);
- for (i = 0; i < initial_open_count; i++) {
- if (!mm_serial_port_open (self, error)) {
- g_prefix_error (error, "Couldn't reopen port (%u): ", i);
- return FALSE;
- }
- }
+ if (reopen_time > 0)
+ priv->reopen_id = g_timeout_add (reopen_time, reopen_do, info);
+ else
+ priv->reopen_id = g_idle_add (reopen_do, info);
return TRUE;
}
@@ -1603,6 +1675,7 @@ dispose (GObject *object)
mm_serial_port_close_force (MM_SERIAL_PORT (object));
+ serial_port_reopen_cancel (MM_SERIAL_PORT (object));
mm_serial_port_flash_cancel (MM_SERIAL_PORT (object));
G_OBJECT_CLASS (mm_serial_port_parent_class)->dispose (object);
diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h
index 18806d2e..73e55d9f 100644
--- a/src/mm-serial-port.h
+++ b/src/mm-serial-port.h
@@ -43,6 +43,10 @@
typedef struct _MMSerialPort MMSerialPort;
typedef struct _MMSerialPortClass MMSerialPortClass;
+typedef void (*MMSerialReopenFn) (MMSerialPort *port,
+ GError *error,
+ gpointer user_data);
+
typedef void (*MMSerialFlashFn) (MMSerialPort *port,
GError *error,
gpointer user_data);
@@ -123,7 +127,9 @@ gboolean mm_serial_port_open (MMSerialPort *self,
void mm_serial_port_close (MMSerialPort *self);
gboolean mm_serial_port_reopen (MMSerialPort *self,
- GError **error);
+ guint32 reopen_time,
+ MMSerialReopenFn callback,
+ gpointer user_data);
gboolean mm_serial_port_flash (MMSerialPort *self,
guint32 flash_time,