diff options
author | Dan Williams <dcbw@redhat.com> | 2010-04-29 21:15:17 -0700 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2010-04-29 21:15:17 -0700 |
commit | bfe3dd49edb2c89fee01c141c8c7eec490b665d5 (patch) | |
tree | 8c8e18b3d39195e3a576e19c7dc19f2e8bacefb7 /src/mm-serial-port.c | |
parent | 26a51d6ab9a7bc70840e8a1d30f5e3bb777d9f25 (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.c | 82 |
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); } |