Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,60 @@ AC_SYS_LARGEFILE
# Define size_t if not defined as standard.
AC_TYPE_SIZE_T

# Check to see if the baud rates in termios.h seem sane.
AC_CACHE_CHECK([if <termios.h> is sane], [sp_cv_termios_sane], [
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <termios.h>
#if (!defined(B0) || B0 == 0) \
&& (!defined(B50) || B50 == 50) \
&& (!defined(B75) || B75 == 75) \
&& (!defined(B110) || B110 == 110) \
&& (!defined(B134) || B134 == 134) \
&& (!defined(B150) || B150 == 150) \
&& (!defined(B200) || B200 == 200) \
&& (!defined(B300) || B300 == 300) \
&& (!defined(B600) || B600 == 600) \
&& (!defined(B1200) || B1200 == 1200) \
&& (!defined(B1800) || B1800 == 1800) \
&& (!defined(B2400) || B2400 == 2400) \
&& (!defined(B4800) || B4800 == 4800) \
&& (!defined(B7200) || B7200 == 7200) \
&& (!defined(B9600) || B9600 == 9600) \
&& (!defined(B14400) || B14400 == 14400) \
&& (!defined(B19200) || B19200 == 19200) \
&& (!defined(B28800) || B28800 == 28800) \
&& (!defined(B33600) || B33600 == 33600) \
&& (!defined(B38400) || B38400 == 38400) \
&& (!defined(B57600) || B57600 == 57600) \
&& (!defined(B76800) || B76800 == 76800) \
&& (!defined(B115200) || B115200 == 115200) \
&& (!defined(B153600) || B153600 == 153600) \
&& (!defined(B230400) || B230400 == 230400) \
&& (!defined(B307200) || B307200 == 307200) \
&& (!defined(B460800) || B460800 == 460800) \
&& (!defined(B500000) || B500000 == 500000) \
&& (!defined(B576000) || B576000 == 576000) \
&& (!defined(B614400) || B614400 == 614400) \
&& (!defined(B921600) || B921600 == 921600) \
&& (!defined(B1000000) || B1000000 == 1000000) \
&& (!defined(B1152000) || B1152000 == 1152000) \
&& (!defined(B1500000) || B1500000 == 1500000) \
&& (!defined(B2000000) || B2000000 == 2000000) \
&& (!defined(B2500000) || B2500000 == 2500000) \
&& (!defined(B3000000) || B3000000 == 3000000) \
&& (!defined(B3500000) || B3500000 == 3500000) \
&& (!defined(B4000000) || B4000000 == 4000000) \
&& (!defined(B5000000) || B5000000 == 5000000) \
&& (!defined(B10000000) || B10000000 == 10000000)
# define TERMIOS_SPEED_T_SANE 1
#else
# error "<termios.h> uses stupid constants"
#endif
]])], [sp_cv_termios_sane=yes], [sp_cv_termios_sane=no])])

AS_IF([test x$sp_cv_termios_sane = xyes],
[AC_DEFINE(HAVE_SANE_TERMIOS, 1, [<termios.h> speeds are sane])],
[
# Check for specific termios structures.
AC_CHECK_TYPES([struct termios2],,,
[[#include <linux/termios.h>]])
Expand All @@ -121,7 +175,7 @@ AC_CHECK_MEMBERS([struct termios.c_ispeed, struct termios.c_ospeed,
# Check for the BOTHER definition, needed for setting arbitrary baud rates.
# We can't just #ifdef BOTHER in the code, because of the separation between
# code using libc headers and code using kernel termios.h headers.
AC_CHECK_DECLS([BOTHER],,, [[#include <linux/termios.h>]])
AC_CHECK_DECLS([BOTHER],,, [[#include <linux/termios.h>]])])

# Check for serial_struct.
AC_CHECK_TYPES([struct serial_struct],,, [[#include <linux/serial.h>]])
Expand Down
7 changes: 5 additions & 2 deletions libserialport_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,11 @@
#endif

/* Non-standard baudrates are not available everywhere. */
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && HAVE_DECL_BOTHER
#define USE_TERMIOS_SPEED
#ifdef HAVE_SANE_TERMIOS
/* Directly supported by termios */
# undef USE_TERMIOS_SPEED
#elif (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && HAVE_DECL_BOTHER
# define USE_TERMIOS_SPEED
#endif

struct sp_port {
Expand Down
14 changes: 9 additions & 5 deletions linux_termios.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
*/

/*
* At the time of writing, glibc does not support the Linux kernel interfaces
* for setting non-standard baud rates and flow control. We therefore have to
* prepare the correct ioctls ourselves, for which we need the declarations in
* linux/termios.h.
* glibc before version 2.42 does not support the Linux kernel
* interfaces for setting non-standard baud rates and flow control. We
* therefore have to prepare the correct ioctls ourselves, for which
* we need the declarations in linux/termios.h.
*
* We can't include linux/termios.h in serialport.c however, because its
* contents conflict with the termios.h provided by glibc. So this file exists
Expand All @@ -38,6 +38,8 @@
#include <linux/termios.h>
#include "linux_termios.h"

#ifndef HAVE_SANE_TERMIOS

SP_PRIV unsigned long get_termios_get_ioctl(void)
{
#ifdef HAVE_STRUCT_TERMIOS2
Expand Down Expand Up @@ -86,7 +88,7 @@ SP_PRIV void set_termios_speed(void *data, int speed)
#else
struct termios *term = (struct termios *) data;
#endif
term->c_cflag &= ~CBAUD;
term->c_cflag &= ~(CBAUD | CIBAUD);
term->c_cflag |= BOTHER;
term->c_ispeed = term->c_ospeed = speed;
}
Expand Down Expand Up @@ -127,3 +129,5 @@ SP_PRIV void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr)
termx->x_cflag |= DSRXON;
}
#endif

#endif
23 changes: 20 additions & 3 deletions serialport.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "libserialport_internal.h"

#ifndef HAVE_SANE_TERMIOS
static const struct std_baudrate std_baudrates[] = {
#ifdef _WIN32
/*
Expand All @@ -42,8 +43,8 @@ static const struct std_baudrate std_baudrates[] = {
#endif
#endif
};

#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
#endif

void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;

Expand Down Expand Up @@ -1692,7 +1693,9 @@ static enum sp_return set_flow(int fd, struct port_data *data)
static enum sp_return get_config(struct sp_port *port, struct port_data *data,
struct sp_port_config *config)
{
#ifndef HAVE_SANE_TERMIOS
unsigned int i;
#endif

TRACE("%p, %p, %p", port, data, config);

Expand Down Expand Up @@ -1811,22 +1814,26 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data,
data->termiox_supported = 0;
#endif

#ifdef HAVE_SANE_TERMIOS
config->baudrate = cfgetospeed(&data->term);
#else
for (i = 0; i < NUM_STD_BAUDRATES; i++) {
if (cfgetispeed(&data->term) == std_baudrates[i].index) {
if (cfgetospeed(&data->term) == std_baudrates[i].index) {
config->baudrate = std_baudrates[i].value;
break;
}
}

if (i == NUM_STD_BAUDRATES) {
#ifdef __APPLE__
config->baudrate = (int)data->term.c_ispeed;
config->baudrate = (int)data->term.c_ospeed;
#elif defined(USE_TERMIOS_SPEED)
TRY(get_baudrate(port->fd, &config->baudrate));
#else
config->baudrate = -1;
#endif
}
#endif

switch (data->term.c_cflag & CSIZE) {
case CS8:
Expand Down Expand Up @@ -1898,7 +1905,10 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data,
static enum sp_return set_config(struct sp_port *port, struct port_data *data,
const struct sp_port_config *config)
{
#ifndef HAVE_SANE_TERMIOS
unsigned int i;
#endif

#ifdef __APPLE__
BAUD_TYPE baud_nonstd;

Expand Down Expand Up @@ -2064,6 +2074,12 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
int controlbits;

if (config->baudrate >= 0) {
#ifdef HAVE_SANE_TERMIOS
if (cfsetospeed(&data->term, config->baudrate) < 0)
RETURN_FAIL("cfsetospeed() failed");
if (cfsetispeed(&data->term, config->baudrate) < 0)
RETURN_FAIL("cfsetispeed() failed");
#else
for (i = 0; i < NUM_STD_BAUDRATES; i++) {
if (config->baudrate == std_baudrates[i].value) {
if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
Expand All @@ -2088,6 +2104,7 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported");
#endif
}
#endif
}

if (config->bits >= 0) {
Expand Down