+ int ret;
+ char *error;
+ int sp_flags = 0;
+
+ if (!serial) {
+ sr_dbg("Invalid serial port.");
+ return SR_ERR;
+ }
+
+ sr_spew("Opening serial port '%s' (flags %d).", serial->port, flags);
+
+ sp_get_port_by_name(serial->port, &serial->data);
+
+ if (flags & SERIAL_RDWR)
+ sp_flags = (SP_MODE_READ | SP_MODE_WRITE);
+ else if (flags & SERIAL_RDONLY)
+ sp_flags = SP_MODE_READ;
+
+ serial->nonblocking = (flags & SERIAL_NONBLOCK) ? 1 : 0;
+
+ ret = sp_open(serial->data, sp_flags);
+
+ switch (ret) {
+ case SP_ERR_ARG:
+ sr_err("Attempt to open serial port with invalid parameters.");
+ return SR_ERR_ARG;
+ case SP_ERR_FAIL:
+ error = sp_last_error_message();
+ sr_err("Error opening port: %s.", error);
+ sp_free_error_message(error);
+ return SR_ERR;
+ }
+
+#ifndef _WIN32
+ sp_get_port_handle(serial->data, &serial->fd);
+#endif
+
+ if (serial->serialcomm)
+ return serial_set_paramstr(serial, serial->serialcomm);
+ else
+ return SR_OK;
+}
+
+/**
+ * Close the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int serial_close(struct sr_serial_dev_inst *serial)
+{
+ int ret;
+ char *error;
+
+ if (!serial) {
+ sr_dbg("Invalid serial port.");
+ return SR_ERR;
+ }
+
+ if (serial->fd == -1) {
+ sr_dbg("Cannot close unopened serial port %s (fd %d).",
+ serial->port, serial->fd);
+ return SR_ERR;
+ }
+
+ sr_spew("Closing serial port %s (fd %d).", serial->port, serial->fd);
+
+ ret = sp_close(serial->data);
+ sp_free_port(serial->data);
+
+ switch (ret) {
+ case SP_ERR_ARG:
+ sr_err("Attempt to close an invalid serial port.");
+ return SR_ERR_ARG;
+ case SP_ERR_FAIL:
+ error = sp_last_error_message();
+ sr_err("Error closing port: %s.", error);
+ sp_free_error_message(error);
+ return SR_ERR;
+ }
+
+ serial->fd = -1;
+
+ return SR_OK;
+}
+
+/**
+ * Flush serial port buffers.
+ *
+ * @param serial Previously initialized serial port structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial)
+{
+ int ret;
+ char *error;
+
+ if (!serial) {
+ sr_dbg("Invalid serial port.");
+ return SR_ERR;
+ }
+
+ if (serial->fd == -1) {
+ sr_dbg("Cannot flush unopened serial port %s (fd %d).",
+ serial->port, serial->fd);
+ return SR_ERR;
+ }
+
+ sr_spew("Flushing serial port %s (fd %d).", serial->port, serial->fd);
+
+ ret = sp_flush(serial->data, SP_BUF_BOTH);
+
+ switch (ret) {
+ case SP_ERR_ARG:
+ sr_err("Attempt to flush an invalid serial port.");
+ return SR_ERR_ARG;
+ case SP_ERR_FAIL:
+ error = sp_last_error_message();
+ sr_err("Error flushing port: %s.", error);
+ sp_free_error_message(error);
+ return SR_ERR;
+ }
+
+ return SR_OK;
+}
+
+/**
+ * Write a number of bytes to the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer containing the bytes to write.
+ * @param count Number of bytes to write.
+ *
+ * @return The number of bytes written, or a negative error code upon failure.
+ */
+SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
+ const void *buf, size_t count)
+{
+ ssize_t ret;
+ char *error;
+
+ if (!serial) {
+ sr_dbg("Invalid serial port.");
+ return SR_ERR;
+ }
+
+ if (serial->fd == -1) {
+ sr_dbg("Cannot use unopened serial port %s (fd %d).",
+ serial->port, serial->fd);
+ return SR_ERR;
+ }
+
+ if (serial->nonblocking)
+ ret = sp_nonblocking_write(serial->data, buf, count);
+ else
+ ret = sp_blocking_write(serial->data, buf, count, 0);
+
+ switch (ret) {
+ case SP_ERR_ARG:
+ sr_err("Attempted serial port write with invalid arguments.");
+ return SR_ERR_ARG;
+ case SP_ERR_FAIL:
+ error = sp_last_error_message();
+ sr_err("Write error: %s.", error);
+ sp_free_error_message(error);
+ return SR_ERR;
+ }
+
+ sr_spew("Wrote %d/%d bytes (fd %d).", ret, count, serial->fd);
+
+ return ret;
+}
+
+/**
+ * Read a number of bytes from the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer where to store the bytes that are read.
+ * @param count The number of bytes to read.
+ *
+ * @return The number of bytes read, or a negative error code upon failure.
+ */
+SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
+ size_t count)
+{
+ ssize_t ret;
+ char *error;
+
+ if (!serial) {
+ sr_dbg("Invalid serial port.");
+ return SR_ERR;
+ }
+
+ if (serial->fd == -1) {
+ sr_dbg("Cannot use unopened serial port %s (fd %d).",
+ serial->port, serial->fd);
+ return SR_ERR;