[PATCH 5/8] port-serial: new internal method to run tcsetattr()
Aleksander Morgado
aleksander at aleksander.es
Tue Apr 18 17:10:04 UTC 2017
On 25/03/17 19:32, Aleksander Morgado wrote:
> The method takes care of looping if EAGAIN errors happen, as well as
> checking whether all attributes were set or not.
> ---
This has been merged to git master.
> 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);
> }
>
> /*****************************************************************************/
>
--
Aleksander
https://aleksander.es
More information about the ModemManager-devel
mailing list