[PATCH 5/8] port-serial: new internal method to run tcsetattr()
Aleksander Morgado
aleksander at aleksander.es
Sat Mar 25 18:32:14 UTC 2017
The method takes care of looping if EAGAIN errors happen, as well as
checking whether all attributes were set or not.
---
src/mm-port-serial.c | 119 ++++++++++++++++++++++++---------------------------
1 file changed, 57 insertions(+), 62 deletions(-)
diff --git a/src/mm-port-serial.c b/src/mm-port-serial.c
index 2b6b92d3..f2b97a02 100644
--- a/src/mm-port-serial.c
+++ b/src/mm-port-serial.c
@@ -347,9 +347,62 @@ parse_stopbits (guint i)
}
static gboolean
+internal_tcsetattr (MMPortSerial *self,
+ gint fd,
+ const struct termios *options,
+ GError **error)
+{
+ guint count;
+ struct termios other;
+
+#define MAX_TCSETATTR_RETRIES 4
+
+ for (count = 0; count < MAX_TCSETATTR_RETRIES; count++) {
+ /* try to set the new port attributes */
+ errno = 0;
+ if (tcsetattr (fd, TCSANOW, options) == 0)
+ break;
+
+ /* hard error if not EAGAIN */
+ if (errno != EAGAIN) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "couldn't set serial port attributes: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ /* try a few times if EAGAIN */
+ g_usleep (100000);
+ }
+
+ /* too many retries? */
+ if (count == MAX_TCSETATTR_RETRIES) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "couldn't set serial port attributes: too many retries (%u)", count);
+ return FALSE;
+ }
+
+ /* tcsetattr() returns 0 if any of the requested attributes could be set,
+ * so we should double-check that all were set and log if not. Just with
+ * debug level, as we're ignoring this issue all together anyway.
+ */
+ memset (&other, 0, sizeof (struct termios));
+ errno = 0;
+ if (tcgetattr (fd, &other) != 0)
+ mm_dbg ("(%s): couldn't get serial port attributes after setting them: %s",
+ mm_port_get_device (MM_PORT (self)), g_strerror (errno));
+ else if (memcmp (options, &other, sizeof (struct termios)) != 0)
+ mm_dbg ("(%s): port attributes not fully set",
+ mm_port_get_device (MM_PORT (self)));
+
+#undef MAX_TCSETATTR_RETRIES
+
+ return TRUE;
+}
+
+static gboolean
real_config_fd (MMPortSerial *self, int fd, GError **error)
{
- struct termios stbuf, other;
+ struct termios stbuf;
guint speed;
gint bits;
gint parity;
@@ -416,32 +469,7 @@ real_config_fd (MMPortSerial *self, int fd, GError **error)
return FALSE;
}
- if (tcsetattr (fd, TCSANOW, &stbuf) < 0) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "%s: failed to set serial port attributes; errno %d",
- __func__, errno);
- return FALSE;
- }
-
- /* tcsetattr() returns 0 if any of the requested attributes could be set,
- * so we should double-check that all were set and log a warning if not.
- */
- memset (&other, 0, sizeof (struct termios));
- errno = 0;
- if (tcgetattr (fd, &other) != 0) {
- mm_warn ("(%s): tcgetattr() error: %d",
- mm_port_get_device (MM_PORT (self)),
- errno);
- }
-
- if (memcmp (&stbuf, &other, sizeof (other)) != 0) {
- mm_warn ("(%s): port attributes not fully set",
- mm_port_get_device (MM_PORT (self)));
- }
-
- return TRUE;
+ return internal_tcsetattr (self, fd, &stbuf, error);
}
static void
@@ -1576,15 +1604,11 @@ static gboolean
set_speed (MMPortSerial *self, speed_t speed, GError **error)
{
struct termios options;
- int fd, count = 4;
- gboolean success = FALSE;
g_assert (self->priv->fd >= 0);
- fd = self->priv->fd;
-
memset (&options, 0, sizeof (struct termios));
- if (tcgetattr (fd, &options) != 0) {
+ if (tcgetattr (self->priv->fd, &options) != 0) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
@@ -1601,36 +1625,7 @@ set_speed (MMPortSerial *self, speed_t speed, GError **error)
if (self->priv->rts_cts)
options.c_cflag |= (CRTSCTS);
- while (count-- > 0) {
- if (tcsetattr (fd, TCSANOW, &options) == 0) {
- success = TRUE;
- break; /* Operation successful */
- }
-
- /* Try a few times if EAGAIN */
- if (errno == EAGAIN)
- g_usleep (100000);
- else {
- /* If not EAGAIN, hard error */
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "%s: tcsetattr() error %d",
- __func__, errno);
- return FALSE;
- }
- }
-
- if (!success) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "%s: tcsetattr() retry timeout",
- __func__);
- return FALSE;
- }
-
- return TRUE;
+ return internal_tcsetattr (self, self->priv->fd, &options, error);
}
/*****************************************************************************/
--
2.12.0
More information about the ModemManager-devel
mailing list