diff --git a/configure.ac b/configure.ac index d71833f..ae6406e 100644 --- a/configure.ac +++ b/configure.ac @@ -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 is sane], [sp_cv_termios_sane], [ + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +#include +#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 " 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, [ speeds are sane])], +[ # Check for specific termios structures. AC_CHECK_TYPES([struct termios2],,, [[#include ]]) @@ -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 ]]) +AC_CHECK_DECLS([BOTHER],,, [[#include ]])]) # Check for serial_struct. AC_CHECK_TYPES([struct serial_struct],,, [[#include ]]) diff --git a/libserialport_internal.h b/libserialport_internal.h index 57346d6..88bb9f6 100644 --- a/libserialport_internal.h +++ b/libserialport_internal.h @@ -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 { diff --git a/linux_termios.c b/linux_termios.c index 3630e57..dad0e9c 100644 --- a/linux_termios.c +++ b/linux_termios.c @@ -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 @@ -38,6 +38,8 @@ #include #include "linux_termios.h" +#ifndef HAVE_SANE_TERMIOS + SP_PRIV unsigned long get_termios_get_ioctl(void) { #ifdef HAVE_STRUCT_TERMIOS2 @@ -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; } @@ -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 diff --git a/serialport.c b/serialport.c index b3b9249..f1279cf 100644 --- a/serialport.c +++ b/serialport.c @@ -23,6 +23,7 @@ #include "libserialport_internal.h" +#ifndef HAVE_SANE_TERMIOS static const struct std_baudrate std_baudrates[] = { #ifdef _WIN32 /* @@ -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; @@ -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); @@ -1811,8 +1814,11 @@ 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; } @@ -1820,13 +1826,14 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data, 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: @@ -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; @@ -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) @@ -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) {