aboutsummaryrefslogtreecommitdiff
path: root/src/mm-serial-port.c
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-04-29 21:15:17 -0700
committerDan Williams <dcbw@redhat.com>2010-04-29 21:15:17 -0700
commitbfe3dd49edb2c89fee01c141c8c7eec490b665d5 (patch)
tree8c8e18b3d39195e3a576e19c7dc19f2e8bacefb7 /src/mm-serial-port.c
parent26a51d6ab9a7bc70840e8a1d30f5e3bb777d9f25 (diff)
core: refcount serial port open/close
This specifically fixes a regression with Novatel GSM secondary AT port enablement, where the inital pin check closed the port before the Novatel plugin could send the command to flip secondary ports to AT mode. But it's useful elsewhere too, and simplifies a bunch of the PIN checking code which had to use various ugly methods to track whether to close the port or not after checking the PIN.
Diffstat (limited to 'src/mm-serial-port.c')
-rw-r--r--src/mm-serial-port.c82
1 files changed, 62 insertions, 20 deletions
diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c
index b7fdf275..37f1bb09 100644
--- a/src/mm-serial-port.c
+++ b/src/mm-serial-port.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2008 - 2009 Novell, Inc.
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
*/
#define _GNU_SOURCE /* for strcasestr() */
@@ -51,6 +51,7 @@ enum {
#define MM_SERIAL_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_SERIAL_PORT, MMSerialPortPrivate))
typedef struct {
+ guint32 open_count;
int fd;
GHashTable *reply_cache;
GIOChannel *channel;
@@ -601,7 +602,7 @@ data_available (GIOChannel *source,
if (condition & G_IO_HUP) {
if (priv->response->len)
g_byte_array_remove_range (priv->response, 0, priv->response->len);
- mm_serial_port_close (self);
+ mm_serial_port_close_force (self);
return FALSE;
}
@@ -688,13 +689,13 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
priv = MM_SERIAL_PORT_GET_PRIVATE (self);
- if (priv->fd >= 0) {
+ device = mm_port_get_device (MM_PORT (self));
+
+ if (priv->open_count) {
/* Already open */
- return TRUE;
+ goto success;
}
- device = mm_port_get_device (MM_PORT (self));
-
g_message ("(%s) opening serial device...", device);
devfile = g_strdup_printf ("/dev/%s", device);
errno = 0;
@@ -716,9 +717,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
if (ioctl (priv->fd, TIOCEXCL) < 0) {
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED,
"Could not lock serial device %s: %s", device, strerror (errno));
- close (priv->fd);
- priv->fd = -1;
- return FALSE;
+ goto error;
}
/* Flush any waiting IO */
@@ -727,17 +726,12 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
if (tcgetattr (priv->fd, &priv->old_t) < 0) {
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED,
"Could not open serial device %s: %s", device, strerror (errno));
- close (priv->fd);
- priv->fd = -1;
- return FALSE;
+ goto error;
}
g_warn_if_fail (MM_SERIAL_PORT_GET_CLASS (self)->config_fd);
- if (!MM_SERIAL_PORT_GET_CLASS (self)->config_fd (self, priv->fd, error)) {
- close (priv->fd);
- priv->fd = -1;
- return FALSE;
- }
+ if (!MM_SERIAL_PORT_GET_CLASS (self)->config_fd (self, priv->fd, error))
+ goto error;
priv->channel = g_io_channel_unix_new (priv->fd);
g_io_channel_set_encoding (priv->channel, NULL, NULL);
@@ -749,7 +743,21 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
priv->connected_id = g_signal_connect (self, "notify::" MM_PORT_CONNECTED,
G_CALLBACK (port_connected), NULL);
+success:
+ priv->open_count++;
+ if (mm_options_debug ()) {
+ GTimeVal tv;
+
+ g_get_current_time (&tv);
+ g_debug ("<%ld.%ld> (%s) device open count is %d (open)",
+ tv.tv_sec, tv.tv_usec, device, priv->open_count);
+ }
return TRUE;
+
+error:
+ close (priv->fd);
+ priv->fd = -1;
+ return FALSE;
}
gboolean
@@ -758,18 +766,35 @@ mm_serial_port_is_open (MMSerialPort *self)
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
- return (MM_SERIAL_PORT_GET_PRIVATE (self)->fd >= 0);
+ return !!MM_SERIAL_PORT_GET_PRIVATE (self)->open_count;
}
void
mm_serial_port_close (MMSerialPort *self)
{
MMSerialPortPrivate *priv;
+ const char *device;
int i;
g_return_if_fail (MM_IS_SERIAL_PORT (self));
priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ g_return_if_fail (priv->open_count > 0);
+
+ device = mm_port_get_device (MM_PORT (self));
+
+ priv->open_count--;
+
+ if (mm_options_debug ()) {
+ GTimeVal tv;
+
+ g_get_current_time (&tv);
+ g_debug ("<%ld.%ld> (%s) device open count is %d (close)",
+ tv.tv_sec, tv.tv_usec, device, priv->open_count);
+ }
+
+ if (priv->open_count > 0)
+ return;
if (priv->connected_id) {
g_signal_handler_disconnect (self, priv->connected_id);
@@ -777,7 +802,7 @@ mm_serial_port_close (MMSerialPort *self)
}
if (priv->fd >= 0) {
- g_message ("(%s) closing serial device...", mm_port_get_device (MM_PORT (self)));
+ g_message ("(%s) closing serial device...", device);
mm_port_set_connected (MM_PORT (self), FALSE);
@@ -809,6 +834,22 @@ mm_serial_port_close (MMSerialPort *self)
g_queue_clear (priv->queue);
}
+void
+mm_serial_port_close_force (MMSerialPort *self)
+{
+ MMSerialPortPrivate *priv;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
+
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ g_return_if_fail (priv->open_count > 0);
+
+ /* Force the port to close */
+ priv->open_count = 1;
+ mm_serial_port_close (self);
+}
+
static void
internal_queue_command (MMSerialPort *self,
GByteArray *command,
@@ -1170,7 +1211,8 @@ get_property (GObject *object, guint prop_id,
static void
dispose (GObject *object)
{
- mm_serial_port_close (MM_SERIAL_PORT (object));
+ if (mm_serial_port_is_open (MM_SERIAL_PORT (object)))
+ mm_serial_port_close_force (MM_SERIAL_PORT (object));
G_OBJECT_CLASS (mm_serial_port_parent_class)->dispose (object);
}