diff options
-rw-r--r-- | src/mm-broadband-bearer.c | 75 | ||||
-rw-r--r-- | src/mm-serial-port.c | 97 | ||||
-rw-r--r-- | src/mm-serial-port.h | 8 |
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, |