]> git.ozlabs.org Git - ppp.git/commitdiff
pppd: Add support for arbitrary baud rates via BOTHER on Linux (#278)
authorpali <7141871+pali@users.noreply.github.com>
Sat, 5 Jun 2021 01:43:24 +0000 (03:43 +0200)
committerGitHub <noreply@github.com>
Sat, 5 Jun 2021 01:43:24 +0000 (11:43 +1000)
Most Linux architectures and drivers support arbitrary baud rate BOTHER
values via TCGETS2 and TCSETS2 ioctls in struct termios2.

This patch implements support for BOTHER and struct termios2 which allows
pppd to use any baud rate on Linux systems where architecture and drivers
have support for it.

By default standard values are used.

Support for BOTHER is enabled during compilation when header files have
appropriate definitions of TCGETS2 and TCSETS2 ioctls.

Because there is no glibc support for BOTHER and struct termios2 yet, pppd
defines own BOTHER macro and struct termios2.

Signed-off-by: Pali Rohár <pali@kernel.org>
pppd/pppd.8
pppd/sys-linux.c

index 95051bf028c0885e8e3b3842c9f0dc355f89a40d..cd4b9eba3a49ceb5bd87eaea702500b864f9552f 100644 (file)
@@ -55,8 +55,8 @@ non-privileged user.
 .I speed
 An option that is a decimal number is taken as the desired baud rate
 for the serial device.  On systems such as
-4.4BSD and NetBSD, any speed can be specified.  Other systems
-(e.g. Linux, SunOS) only support the commonly-used baud rates.
+Linux, 4.4BSD and NetBSD, any speed can be specified.  Other systems
+(e.g. SunOS) only support the commonly-used baud rates.
 .TP
 .B asyncmap \fImap
 This option sets the Async-Control-Character-Map (ACCM) for this end
index b0ad508185336785a80a156a81e9948bb5cd3cc4..c05047c765c1d6cad5e1cf38ce9897850d8a9658 100644 (file)
 
 #if !defined(__GLIBC__) || __GLIBC__ >= 2
 #include <asm/types.h>         /* glibc 2 conflicts with linux/types.h */
+#include <asm/ioctls.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/route.h>
 #include <sys/locks.h>
 #endif
 
+#ifndef BOTHER
+#define BOTHER 0010000
+#endif
+struct termios2 {
+       unsigned int c_iflag;
+       unsigned int c_oflag;
+       unsigned int c_cflag;
+       unsigned int c_lflag;
+       unsigned char c_line;
+       unsigned char c_cc[19];
+       unsigned int c_ispeed;
+       unsigned int c_ospeed;
+};
+
 #ifdef INET6
 #ifndef _LINUX_IN6_H
 /*
@@ -898,6 +913,12 @@ struct speed {
 #ifdef B460800
     { 460800, B460800 },
 #endif
+#ifdef B500000
+    { 500000, B500000 },
+#endif
+#ifdef B576000
+    { 576000, B576000 },
+#endif
 #ifdef B921600
     { 921600, B921600 },
 #endif
@@ -942,7 +963,6 @@ static int translate_speed (int bps)
            if (bps == speedp->speed_int)
                return speedp->speed_val;
        }
-       warn("speed %d not supported", bps);
     }
     return 0;
 }
@@ -1021,26 +1041,57 @@ void set_up_tty(int tty_fd, int local)
     if (stop_bits >= 2)
        tios.c_cflag |= CSTOPB;
 
-    speed = translate_speed(inspeed);
-    if (speed) {
-       cfsetospeed (&tios, speed);
-       cfsetispeed (&tios, speed);
+    if (inspeed) {
+       speed = translate_speed(inspeed);
+       if (speed) {
+           cfsetospeed (&tios, speed);
+           cfsetispeed (&tios, speed);
+           speed = cfgetospeed(&tios);
+       }
+       baud_rate = baud_rate_of(speed);
     }
-/*
- * We can't proceed if the serial port speed is B0,
- * since that implies that the serial port is disabled.
- */
     else {
        speed = cfgetospeed(&tios);
-       if (speed == B0)
-           fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+       baud_rate = baud_rate_of(speed);
     }
 
     while (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0 && !ok_error(errno))
        if (errno != EINTR)
            fatal("tcsetattr: %m (line %d)", __LINE__);
 
-    baud_rate    = baud_rate_of(speed);
+/* Most Linux architectures and drivers support arbitrary baud rate values via BOTHER */
+#ifdef TCGETS2
+    if (!baud_rate) {
+       struct termios2 tios2;
+       if (ioctl(tty_fd, TCGETS2, &tios2) == 0) {
+           if (inspeed) {
+               tios2.c_cflag &= ~CBAUD;
+               tios2.c_cflag |= BOTHER;
+               tios2.c_ispeed = inspeed;
+               tios2.c_ospeed = inspeed;
+#ifdef TCSETS2
+               if (ioctl(tty_fd, TCSETS2, &tios2) == 0)
+                   baud_rate = inspeed;
+#endif
+           } else {
+               if ((tios2.c_cflag & CBAUD) == BOTHER && tios2.c_ospeed)
+                   baud_rate = tios2.c_ospeed;
+           }
+       }
+    }
+#endif
+
+/*
+ * We can't proceed if the serial port baud rate is unknown,
+ * since that implies that the serial port is disabled.
+ */
+    if (!baud_rate) {
+       if (inspeed)
+           fatal("speed %d not supported", inspeed);
+       else
+           fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+    }
+
     restore_term = 1;
 }