diff --git a/Makefile b/Makefile index d64e77e..b909baf 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ linenoise-1.0/linenoise.o : linenoise-1.0/linenoise.c linenoise-1.0/linenoise.h #CPPFLAGS += -DNO_HELP -OBJS += picocom.o term.o fdio.o split.o termios2.o custbaud_bsd.o +OBJS += picocom.o term.o fdio.o split.o custbaud.o termios2.o custbaud_bsd.o picocom : $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) @@ -59,6 +59,7 @@ split.o : split.c split.h fdio.o : fdio.c fdio.h termios2.o : termios2.c termios2.h termbits2.h custbaud.h custbaud_bsd.o : custbaud_bsd.c custbaud_bsd.h custbaud.h +custbaud.o : custbaud.c custbaud.h .c.o : $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< @@ -90,7 +91,7 @@ picocom.1.pdf : picocom.1 clean: rm -f picocom.o term.o fdio.o split.o rm -f linenoise-1.0/linenoise.o - rm -f termios2.o custbaud_bsd.o + rm -f custbaud.o termios2.o custbaud_bsd.o rm -f *~ rm -f \#*\# diff --git a/README.md b/README.md index ed3893a..403cd61 100644 --- a/README.md +++ b/README.md @@ -326,3 +326,45 @@ Some interesting points: Again, this is only *one* possible setup. There are countless other variations and elaborations you can try. Be creative! + +## Some notes on custom baudrate support + +Custom baudrate support gives you the ability to set arbitrary +baudrate values (like 1234, or 42000, etc) to a serial port, provided +that the underlying driver can handle this. Since release 2.0, picocom +can be compiled with custom baudrate support for some systems. Since +release 3.1 picocom is compiled with custom baudrate support enabled +by default on some systems (like Linux, kernels > 2.6, on ix86 and +ix86_64, modern intel macs, and some other BSDs). In any case, you can +explicitly ask for custom baudrate support to be enabled by compiling +picocom like this: + + CPPFLAGS=-DUSE_CUSTOM_BAUD make clean + CPPFLAGS=-DUSE_CUSTOM_BAUD make + +If custom baudrate support is not available for your system, the +compilation will fail. Similarly, you can ask for custom baudrate +support to be disabled by compiling like: + + CPPFLAGS=-DNO_CUSTOM_BAUD make clean + CPPFLAGS=-DNO_CUSTOM_BAUD make + +When picocom is compiled with custom baudrate support on Linux, it +uses a new set of ioctl's (TCGETS2, TCSETSF2 vs TCGETS, TCSETSF, etc) +to access the serial ports. It is not impossible that some serial +devices may not accept these new ioctl's (though they should). In +order to be able to use picocom even with such devices, and without +recompiling it, you can disable the custom baudrate support at +runtime, and force picocom to use the "old" ioctls. To do this +(starting with release 3.2) just define the environment variable +`NO_CUSTOM_BAUD` before running picocom. Something like this: + + NO_CUSTOM_BAUD=1 picocom ... + +This only applies to Linux, and to picocom binaries that have been +compiled with custom baudrate support. + +To see if your binary has been compiled with custom baudrate support, +and / or if it has detected the `NO_CUSTOM_BAUD` variable, run it with +the **--help** option, and take a look at the first few lines of +output. diff --git a/custbaud.c b/custbaud.c new file mode 100644 index 0000000..7b6bd5d --- /dev/null +++ b/custbaud.c @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: + * + * custbaud.c + * + * by Nick Patavalis (npat@efault.net) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include +#include +#include +#include "custbaud.h" + +#ifndef USE_CUSTOM_BAUD + +int use_custom_baud() { return 0; } + +int cfsetispeed_custom(struct termios *tios, int speed) { errno = EINVAL; return -1; } +int cfsetospeed_custom(struct termios *tios, int speed) { errno = EINVAL; return -1; } +int cfgetispeed_custom(const struct termios *tios) { errno = EINVAL; return -1; } +int cfgetospeed_custom(const struct termios *tios) { errno = EINVAL; return -1; } + +#else /* USE_CUSTOM_BAUD */ + +int +use_custom_baud() +{ +#ifdef __linux__ + static int use = -1; + if ( use < 0 ) + use = getenv("NO_CUSTOM_BAUD") ? 0 : 1; + return use; +#else + return 1; +#endif +} + +#endif /* of ndef USE_CUSTOM_BAUD */ + +/**************************************************************************/ + +/* + * Local Variables: + * mode:c + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/custbaud.h b/custbaud.h index 48151a4..120aa89 100644 --- a/custbaud.h +++ b/custbaud.h @@ -87,6 +87,14 @@ #endif /* of ndef NO_CUSTOM_BAUD else */ +#include + +int use_custom_baud(); +int cfsetispeed_custom(struct termios *tios, int speed); +int cfsetospeed_custom(struct termios *tios, int speed); +int cfgetispeed_custom(const struct termios *tios); +int cfgetospeed_custom(const struct termios *tios); + #endif /* CUSTBAUD_H */ /**************************************************************************/ diff --git a/custbaud_bsd.c b/custbaud_bsd.c index 092f986..f88d1db 100644 --- a/custbaud_bsd.c +++ b/custbaud_bsd.c @@ -71,11 +71,11 @@ int cfsetispeed_custom(struct termios *tiop, int speed) { return cfsetispeed(tiop, speed); } -int cfgetospeed_custom(struct termios *tiop) { +int cfgetospeed_custom(const struct termios *tiop) { return cfgetospeed(tiop); } -int cfgetispeed_custom(struct termios *tiop) { +int cfgetispeed_custom(const struct termios *tiop) { return cfgetispeed(tiop); } diff --git a/custbaud_bsd.h b/custbaud_bsd.h index 459a8f3..a6ab8a9 100644 --- a/custbaud_bsd.h +++ b/custbaud_bsd.h @@ -87,8 +87,8 @@ int cfsetospeed_custom(struct termios *tiop, int speed); int cfsetispeed_custom(struct termios *tiop, int speed); -int cfgetospeed_custom(struct termios *tiop); -int cfgetispeed_custom(struct termios *tiop); +int cfgetospeed_custom(const struct termios *tiop); +int cfgetispeed_custom(const struct termios *tiop); /***************************************************************************/ diff --git a/picocom.c b/picocom.c index 66b60b6..96021a1 100644 --- a/picocom.c +++ b/picocom.c @@ -1626,6 +1626,8 @@ show_usage(char *name) #endif #ifdef USE_CUSTOM_BAUD printf(" USE_CUSTOM_BAUD is enabled\n"); + if ( ! use_custom_baud() ) + printf(" NO_CUSTOM_BAUD is set\n"); #endif printf("\nUsage is: %s [options] \n", s); diff --git a/term.c b/term.c index 115b5bb..b45ab3d 100644 --- a/term.c +++ b/term.c @@ -312,11 +312,10 @@ Bspeed(speed_t code) int term_baud_ok(int baud) { -#ifndef USE_CUSTOM_BAUD - return (Bcode(baud) != BNONE) ? 1 : 0; -#else - return (baud >= 0); -#endif + if ( use_custom_baud() ) + return (baud >= 0); + else + return (Bcode(baud) != BNONE) ? 1 : 0; } int @@ -817,7 +816,11 @@ term_set_baudrate (int fd, int baudrate) /* ispeed = 0, means same as ospeed (see POSIX) */ cfsetispeed(&tio, B0); } else { -#ifdef USE_CUSTOM_BAUD + if ( ! use_custom_baud() ) { + term_errno = TERM_EBAUD; + rval = -1; + break; + } r = cfsetospeed_custom(&tio, baudrate); if ( r < 0 ) { term_errno = TERM_ESETOSPEED; @@ -826,11 +829,6 @@ term_set_baudrate (int fd, int baudrate) } /* ispeed = 0, means same as ospeed (see POSIX) */ cfsetispeed(&tio, B0); -#else /* ! defined USE_CUSTOM_BAUD */ - term_errno = TERM_EBAUD; - rval = -1; - break; -#endif /* of USE_CUSTOM_BAUD */ } term.nexttermios[i] = tio; @@ -857,23 +855,23 @@ term_get_baudrate (int fd, int *ispeed) if ( ispeed ) { code = cfgetispeed(&term.currtermios[i]); *ispeed = Bspeed(code); -#ifdef USE_CUSTOM_BAUD - if ( *ispeed < 0 ) { - *ispeed = cfgetispeed_custom(&term.currtermios[i]); + if ( use_custom_baud() ) { + if ( *ispeed < 0 ) { + *ispeed = cfgetispeed_custom(&term.currtermios[i]); + } } -#endif } code = cfgetospeed(&term.currtermios[i]); ospeed = Bspeed(code); if ( ospeed < 0 ) { -#ifdef USE_CUSTOM_BAUD + if ( ! use_custom_baud() ) { + term_errno = TERM_EGETSPEED; + break; + } ospeed = cfgetospeed_custom(&term.currtermios[i]); if ( ospeed < 0 ) { term_errno = TERM_EGETSPEED; } -#else - term_errno = TERM_EGETSPEED; -#endif } } while (0); diff --git a/termios2.c b/termios2.c index 97c3be0..433040b 100644 --- a/termios2.c +++ b/termios2.c @@ -59,6 +59,8 @@ tc2setattr(int fd, int optional_actions, const struct termios *tios) struct termios2 t2; int cmd; + if ( ! use_custom_baud() ) return tcsetattr(fd, optional_actions, tios); + switch (optional_actions) { case TCSANOW: cmd = IOCTL_SETS; @@ -93,6 +95,8 @@ tc2getattr(int fd, struct termios *tios) size_t i; int r; + if ( ! use_custom_baud() ) return tcgetattr(fd, tios); + r = ioctl(fd, IOCTL_GETS, &t2); if (r < 0) return r; @@ -126,6 +130,8 @@ tc2getattr(int fd, struct termios *tios) int cf2setispeed(struct termios *tios, speed_t speed) { + if ( ! use_custom_baud() ) return cfsetispeed(tios, speed); + if ( (speed & ~CBAUD) != 0 && (speed < B57600 || speed > __MAX_BAUD) ) { errno = EINVAL; @@ -139,8 +145,10 @@ cf2setispeed(struct termios *tios, speed_t speed) } speed_t -cf2getispeed(struct termios *tios) +cf2getispeed(const struct termios *tios) { + if ( ! use_custom_baud() ) return cfgetispeed(tios); + return (tios->c_cflag >> IBSHIFT) & (CBAUD | CBAUDEX); } @@ -150,6 +158,8 @@ cf2getispeed(struct termios *tios) int cf2setospeed_custom(struct termios *tios, int speed) { + if ( ! use_custom_baud() ) { errno = EINVAL; return -1; } + if ( speed <= 0 ) { errno = EINVAL; return -1; @@ -164,6 +174,8 @@ cf2setospeed_custom(struct termios *tios, int speed) int cf2setispeed_custom(struct termios *tios, int speed) { + if ( ! use_custom_baud() ) { errno = EINVAL; return -1; } + if ( speed < 0 ) { errno = EINVAL; return -1; diff --git a/termios2.h b/termios2.h index e13b0e3..8fd285d 100644 --- a/termios2.h +++ b/termios2.h @@ -55,12 +55,12 @@ int tc2getattr(int fd, struct termios *tios); * old one, supports different input and output speeds for a * device. The "speed" argument must be (and the return value will be) * one of the standard "Bxxxx" macros. If cf2getispeed() or - * cfgetospeed(3) return CBAUDEX, then the respective baudrate is a + * cfgetospeed(3) return BOTHER, then the respective baudrate is a * custom one. Read the "termios.c_ispeed" / "termios.c_ospeed" fields * to get the custom value (as a numeric speed). */ int cf2setispeed(struct termios *tios, speed_t speed); -speed_t cf2getispeed(struct termios *tios); +speed_t cf2getispeed(const struct termios *tios); /* Use these to set *custom* input and output baudrates for a * device. The "speed" argument must be a numeric baudrate value diff --git a/termios2.txt b/termios2.txt index 67f50f4..9a11a7a 100644 --- a/termios2.txt +++ b/termios2.txt @@ -72,7 +72,8 @@ called: "the CIBAUD field"), together with field "c_ispeed" control the input baudrate. BTW: Usually CBAUD & CBAUDEX == CBAUD. That is, CBAUDEX *is* -one of the CBAUD bits. +one of the CBAUD bits. See end of this file for more on the usual +relationship of CBAUD, CBAUDEX, BOTHER When issuing one of the TCSETS*2 ioctls, everything contained in the "termios2" structure is copied to a kernel-resident structure and the @@ -147,3 +148,27 @@ baudrate values supplied by the serial drivers can be seen in file "tty_termios_encode_baud_rate()" which is what the serial drivers call to notify the kernel about the effective baudrate. + +Baud-codes, CBAUD, CBAUDEX, and BOTHER +-------------------------------------- + +CBAUD = 0010017 ---> 0001 0000 0000 1111 mask +CBUADEX = 0010000 ---> 0001 0000 0000 0000 extender bit +BOTHER = 0010000 ---> 0001 0000 0000 0000 a reserved code + +Usually CBAUD includes CBAUDEX. In any case the mask is always CBAUD & +CBAUDEX (which is usually == CBAUD) + + Basic codes (Bxxx & CBAUDEX == 0) + + B0 > ---0 ---- ---- 0000 + B50 > ---0 ---- ---- 0001 + ... 16 in total ... + B38400 > ---0 ---- ---- 1111 + + Extended codes (Bxxx & CBAUDEX == 1) + + CBAUDEX / BOTHER > ---1 ---- ---- 0000 + B57600 > ---1 ---- ---- 0001 + ... 16 in total ... + B4000000 > ---1 ---- ---- 1111