]> sigrok.org Git - libserialport.git/blobdiff - serialport.c
Minor Doxygen updates/fixes.
[libserialport.git] / serialport.c
index 0a467dea1a74732cde11d144ae564d2b13fe516f..43dc4d3513e1230e2a34a3306de3ccb90bf5cf08 100644 (file)
 #include <sys/syslimits.h>
 #endif
 #ifdef __linux__
+#ifdef HAVE_LIBUDEV
 #include "libudev.h"
+#endif
+#ifndef __ANDROID__
 #include "linux/serial.h"
+#endif
 #include "linux_termios.h"
+
+/* TCGETX/TCSETX is not available everywhere. */
 #if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX)
 #define USE_TERMIOX
 #endif
 #endif
 
+/* TIOCINQ/TIOCOUTQ is not available everywhere. */
+#if !defined(TIOCINQ) && defined(FIONREAD)
+#define TIOCINQ FIONREAD
+#endif
+#if !defined(TIOCOUTQ) && defined(FIONWRITE)
+#define TIOCOUTQ FIONWRITE
+#endif
+
 #ifndef _WIN32
 #include "linux_termios.h"
 #endif
@@ -159,7 +173,11 @@ void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
 #define RETURN_OK() RETURN_CODE(SP_OK);
 #define RETURN_ERROR(err, msg) do { DEBUG_ERROR(err, msg); return err; } while (0)
 #define RETURN_FAIL(msg) do { DEBUG_FAIL(msg); return SP_ERR_FAIL; } while (0)
-#define RETURN_VALUE(fmt, x) do { DEBUG("%s returning " fmt, __func__, x); return x; } while (0)
+#define RETURN_VALUE(fmt, x) do { \
+       typeof(x) _x = x; \
+       DEBUG("%s returning " fmt, __func__, _x); \
+       return _x; \
+} while (0)
 #define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0)
 #define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = SP_ERR_FAIL; } while (0)
 #define TRACE(fmt, ...) DEBUG("%s(" fmt ") called", __func__, ##__VA_ARGS__)
@@ -450,7 +468,7 @@ out_release:
        IOObjectRelease(iter);
 out_done:
 #endif
-#ifdef __linux__
+#if defined(__linux__) && defined(HAVE_LIBUDEV)
        struct udev *ud;
        struct udev_enumerate *ud_enumerate;
        struct udev_list_entry *ud_list;
@@ -523,7 +541,7 @@ out:
                *list_ptr = list;
                RETURN_OK();
        case SP_ERR_SUPP:
-               DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform.");
+               DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
        default:
                if (list)
                        sp_free_port_list(list);
@@ -590,8 +608,9 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
        DEBUG("Opening port %s", port->name);
 
 #ifdef _WIN32
-       DWORD desired_access = 0, flags_and_attributes = 0;
+       DWORD desired_access = 0, flags_and_attributes = 0, errors;
        char *escaped_port_name;
+       COMSTAT status;
 
        /* Prefix port name with '\\.\' to work with ports above COM9. */
        if (!(escaped_port_name = malloc(strlen(port->name + 5))))
@@ -709,6 +728,11 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
        data.term.c_cflag |= (CLOCAL | CREAD | HUPCL);
 #endif
 
+#ifdef _WIN32
+       if (ClearCommError(port->hdl, &errors, &status) == 0)
+               RETURN_FAIL("ClearCommError() failed");
+#endif
+
        ret = set_config(port, &data, &config);
 
        if (ret < 0) {
@@ -799,13 +823,28 @@ enum sp_return sp_drain(struct sp_port *port)
        /* Returns non-zero upon success, 0 upon failure. */
        if (FlushFileBuffers(port->hdl) == 0)
                RETURN_FAIL("FlushFileBuffers() failed");
+       RETURN_OK();
 #else
-       /* Returns 0 upon success, -1 upon failure. */
-       if (tcdrain(port->fd) < 0)
-               RETURN_FAIL("tcdrain() failed");
+       int result;
+       while (1) {
+#ifdef __ANDROID__
+               int arg = 1;
+               result = ioctl(port->fd, TCSBRK, &arg);
+#else
+               result = tcdrain(port->fd);
+#endif
+               if (result < 0) {
+                       if (errno == EINTR) {
+                               DEBUG("tcdrain() was interrupted");
+                               continue;
+                       } else {
+                               RETURN_FAIL("tcdrain() failed");
+                       }
+               } else {
+                       RETURN_OK();
+               }
+       }
 #endif
-
-       RETURN_OK();
 }
 
 enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout)
@@ -890,9 +929,14 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c
                        timersub(&end, &now, &delta);
                }
                result = select(port->fd + 1, NULL, &fds, NULL, timeout ? &delta : NULL);
-               if (result < 0)
-                       RETURN_FAIL("select() failed");
-               if (result == 0) {
+               if (result < 0) {
+                       if (errno == EINTR) {
+                               DEBUG("select() call was interrupted, repeating");
+                               continue;
+                       } else {
+                               RETURN_FAIL("select() failed");
+                       }
+               } else if (result == 0) {
                        DEBUG("write timed out");
                        RETURN_VALUE("%d", bytes_written);
                }
@@ -962,20 +1006,27 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_
                /* Start asynchronous write. */
                if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) {
                        if (GetLastError() == ERROR_IO_PENDING) {
-                               DEBUG("Asynchronous write started");
-                               port->writing = 1;
-                               RETURN_VALUE("%d", ++written);
+                               if (HasOverlappedIoCompleted(&port->write_ovl)) {
+                                       DEBUG("Asynchronous write completed immediately");
+                                       port->writing = 0;
+                                       written++;
+                                       continue;
+                               } else {
+                                       DEBUG("Asynchronous write running");
+                                       port->writing = 1;
+                                       RETURN_VALUE("%d", ++written);
+                               }
                        } else {
                                /* Actual failure of some kind. */
                                RETURN_FAIL("WriteFile() failed");
                        }
                } else {
-                       DEBUG("Single byte written immediately.");
+                       DEBUG("Single byte written immediately");
                        written++;
                }
        }
 
-       DEBUG("All bytes written immediately.");
+       DEBUG("All bytes written immediately");
 
        RETURN_VALUE("%d", written);
 #else
@@ -1060,9 +1111,14 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u
                        timersub(&end, &now, &delta);
                }
                result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL);
-               if (result < 0)
-                       RETURN_FAIL("select() failed");
-               if (result == 0) {
+               if (result < 0) {
+                       if (errno == EINTR) {
+                               DEBUG("select() call was interrupted, repeating");
+                               continue;
+                       } else {
+                               RETURN_FAIL("select() failed");
+                       }
+               } else if (result == 0) {
                        DEBUG("read timed out");
                        RETURN_VALUE("%d", bytes_read);
                }
@@ -1112,7 +1168,8 @@ enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count
                RETURN_FAIL("ReadFile() failed");
 
        /* Get number of bytes read. */
-       GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE);
+       if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
+               RETURN_FAIL("GetOverlappedResult() failed");
 
        RETURN_VALUE("%d", bytes_read);
 #else
@@ -1144,7 +1201,7 @@ enum sp_return sp_input_waiting(struct sp_port *port)
        COMSTAT comstat;
 
        if (ClearCommError(port->hdl, &errors, &comstat) == 0)
-               RETURN_FAIL("ClearComError() failed");
+               RETURN_FAIL("ClearCommError() failed");
        RETURN_VALUE("%d", comstat.cbInQue);
 #else
        int bytes_waiting;
@@ -1167,7 +1224,7 @@ enum sp_return sp_output_waiting(struct sp_port *port)
        COMSTAT comstat;
 
        if (ClearCommError(port->hdl, &errors, &comstat) == 0)
-               RETURN_FAIL("ClearComError() failed");
+               RETURN_FAIL("ClearCommError() failed");
        RETURN_VALUE("%d", comstat.cbOutQue);
 #else
        int bytes_waiting;
@@ -1531,7 +1588,6 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
 
        if (config->parity >= 0) {
                switch (config->parity) {
-               /* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
                case SP_PARITY_NONE:
                        data->dcb.Parity = NOPARITY;
                        break;