From: "H. Peter Anvin (Intel)" hpa@zytor.com
Now when all architectures define BOTHER and IBSHIFT, we can unconditionally rely on these constants. Furthermore, the code can be significantly simplified in a number of places.
Rather than having two tables and needing to be able to keep them in sync at all times, have one auto-generated table. This also lets us avoid the fact that architectures that have CBAUDEX == 0 have BOTHER in a different location that those that don't.
The code for masking CBAUDEX as a fallback is never exercised on any architecture, because for all architectures, either the baud rate table is completely defined for all CBAUD values, or CBAUDEX == 0, so we can just remove it.
Finally, this patch avoids overrunning the baud_table[] for architectures with CBAUDEX == 0.
Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jiri Slaby jslaby@suse.com Cc: Al Viro viro@zeniv.linux.org.uk Cc: Richard Henderson rth@twiddle.net Cc: Ivan Kokshaysky ink@jurassic.park.msu.ru Cc: Matt Turner mattst88@gmail.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Kate Stewart kstewart@linuxfoundation.org Cc: Philippe Ombredanne pombredanne@nexb.com Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Eugene Syromiatnikov esyr@redhat.com Cc: linux-alpha@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: Johan Hovold johan@kernel.org Cc: Alan Cox alan@lxorguk.ukuu.org.uk Cc: stable@vger.kernel.org --- drivers/tty/.gitignore | 1 + drivers/tty/Makefile | 16 ++++ drivers/tty/bmacros.c | 2 + drivers/tty/tty_baudrate.c | 182 ++++++++++++++----------------------- 4 files changed, 85 insertions(+), 116 deletions(-) create mode 100644 drivers/tty/.gitignore create mode 100644 drivers/tty/bmacros.c
diff --git a/drivers/tty/.gitignore b/drivers/tty/.gitignore new file mode 100644 index 000000000000..d436c18a912c --- /dev/null +++ b/drivers/tty/.gitignore @@ -0,0 +1 @@ +bmacros.h diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index c72cafdf32b4..489b222ab1ce 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -35,3 +35,19 @@ obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o obj-$(CONFIG_VCC) += vcc.o
obj-y += ipwireless/ + +# +# Rules for generating the baud rate table +# +CFLAGS_bmacros.o += -Wp,-dM + +$(obj)/tty_baudrate.o: $(obj)/bmacros.h + +quiet_cmd_bmacros = BMACROS $@ + cmd_bmacros = ( \ + sed -nr -e 's/^.define B([0-9]+) .*$$/BTBL(B\1,\1)/p' $< \ + | sort -n -k1.7 > $@ ) || (rm -f $@ ; echo false) + +targets += bmacros.h +$(obj)/bmacros.h: $(obj)/bmacros.i FORCE + $(call if_changed,bmacros) diff --git a/drivers/tty/bmacros.c b/drivers/tty/bmacros.c new file mode 100644 index 000000000000..0af865ff00de --- /dev/null +++ b/drivers/tty/bmacros.c @@ -0,0 +1,2 @@ +/* This file is used to extract the B... macros from header files */ +#include <linux/termios.h> diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 7576ceace571..ec6d3d93ffac 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -9,43 +9,48 @@ #include <linux/tty.h> #include <linux/export.h>
- /* - * Routine which returns the baud rate of the tty - * - * Note that the baud_table needs to be kept in sync with the - * include/asm/termbits.h file. + * Routine which returns the baud rate of the tty. The B... constants + * are extracted from the appropriate header files via + * bmacros.c -> bmacros.h. */ -static const speed_t baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, -#ifdef __sparc__ - 76800, 153600, 307200, 614400, 921600 -#else - 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 + +/* CBAUD mask with CBAUDEX removed */ +#define CBAUDNX (CBAUD & ~CBAUDEX) + +/* Lowest bit in CBAUDEX, if any. CBAUDEX is assumed contiguous. */ +#define CBAUDEL (CBAUDEX & ~(CBAUDEX << 1)) +#if CBAUDEL & (CBAUDEL-1) +# error "CBAUDEX is not contiguous" #endif -};
-#ifndef __sparc__ -static const tcflag_t baud_bits[] = { - B0, B50, B75, B110, B134, B150, B200, B300, B600, - B1200, B1800, B2400, B4800, B9600, B19200, B38400, - B57600, B115200, B230400, B460800, B500000, B576000, - B921600, B1000000, B1152000, B1500000, B2000000, B2500000, - B3000000, B3500000, B4000000 -}; -#else -static const tcflag_t baud_bits[] = { - B0, B50, B75, B110, B134, B150, B200, B300, B600, - B1200, B1800, B2400, B4800, B9600, B19200, B38400, - B57600, B115200, B230400, B460800, B76800, B153600, - B307200, B614400, B921600 +/* Convert from B... constant to table position */ +#define BPOS(x) (((x) & CBAUDNX) + \ + (CBAUDEX ? ((x) & CBAUDEX)/CBAUDEL*(CBAUDNX+1) : 0)) + +/* Convert from table position to B... constant */ +#define BVAL(x) (((x) & CBAUDNX) + (((x)/(CBAUDNX+1)*CBAUDEX) & CBAUDEX)) + +/* Entry into the baud_table */ +#define BTBL(b,v) [BPOS(b)] = (v), + +static const speed_t baud_table[] = { +#include "bmacros.h" }; -#endif
static int n_baud_table = ARRAY_SIZE(baud_table);
+/* Helper function; will be called with cbaud already masked */ +static speed_t _tty_termios_baud_rate(unsigned int cbaud, speed_t bother_speed) +{ + /* Magic token for arbitrary speed via c_ispeed/c_ospeed */ + if (cbaud == BOTHER) + return bother_speed; + + cbaud = BPOS(cbaud); + return (cbaud >= n_baud_table) ? 0 : baud_table[cbaud]; +} + /** * tty_termios_baud_rate * @termios: termios structure @@ -60,24 +65,8 @@ static int n_baud_table = ARRAY_SIZE(baud_table);
speed_t tty_termios_baud_rate(struct ktermios *termios) { - unsigned int cbaud; - - cbaud = termios->c_cflag & CBAUD; - -#ifdef BOTHER - /* Magic token for arbitrary speed via c_ispeed/c_ospeed */ - if (cbaud == BOTHER) - return termios->c_ospeed; -#endif - if (cbaud & CBAUDEX) { - cbaud &= ~CBAUDEX; - - if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~CBAUDEX; - else - cbaud += 15; - } - return baud_table[cbaud]; + return _tty_termios_baud_rate(termios->c_cflag & CBAUD, + termios->c_ospeed); } EXPORT_SYMBOL(tty_termios_baud_rate);
@@ -95,28 +84,15 @@ EXPORT_SYMBOL(tty_termios_baud_rate);
speed_t tty_termios_input_baud_rate(struct ktermios *termios) { -#ifdef IBSHIFT - unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD; - - if (cbaud == B0) - return tty_termios_baud_rate(termios); -#ifdef BOTHER - /* Magic token for arbitrary speed via c_ispeed*/ - if (cbaud == BOTHER) - return termios->c_ispeed; -#endif - if (cbaud & CBAUDEX) { - cbaud &= ~CBAUDEX; + unsigned int cbaud; + speed_t bother_speed = termios->c_ispeed;
- if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~(CBAUDEX << IBSHIFT); - else - cbaud += 15; + cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD; + if (cbaud == B0) { + cbaud = termios->c_cflag & CBAUD; + bother_speed = termios->c_ospeed; } - return baud_table[cbaud]; -#else /* IBSHIFT */ - return tty_termios_baud_rate(termios); -#endif /* IBSHIFT */ + return _tty_termios_baud_rate(cbaud, bother_speed); } EXPORT_SYMBOL(tty_termios_input_baud_rate);
@@ -145,38 +121,27 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate); void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) { - int i = 0; - int ifound = -1, ofound = -1; + int i; + unsigned int ifound, ofound; int iclose = ibaud/50, oclose = obaud/50; - int ibinput = 0; + bool ibinput = false;
- if (obaud == 0) /* CD dropped */ + if (obaud == 0) /* CD dropped */ ibaud = 0; /* Clear ibaud to be sure */
termios->c_ispeed = ibaud; termios->c_ospeed = obaud;
-#ifdef IBSHIFT - if ((termios->c_cflag >> IBSHIFT) & CBAUD) - ibinput = 1; /* An input speed was specified */ -#endif -#ifdef BOTHER + ibinput = ((termios->c_cflag >> IBSHIFT) & CBAUD) != B0; + /* If the user asked for a precise weird speed give a precise weird answer. If they asked for a Bfoo speed they may have problems digesting non-exact replies so fuzz a bit */
- if ((termios->c_cflag & CBAUD) == BOTHER) { + if ((termios->c_cflag & CBAUD) == BOTHER) oclose = 0; - if (!ibinput) - iclose = 0; - } if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER) iclose = 0; -#endif - termios->c_cflag &= ~CBAUD; -#ifdef IBSHIFT - termios->c_cflag &= ~(CBAUD << IBSHIFT); -#endif
/* * Our goal is to find a close match to the standard baud rate @@ -184,43 +149,28 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, * match then report back the speed as a POSIX Bxxxx value by * preference */ - - do { + ofound = ifound = BOTHER; + for (i = 0; i < n_baud_table; i++) { if (obaud - oclose <= baud_table[i] && obaud + oclose >= baud_table[i]) { - termios->c_cflag |= baud_bits[i]; - ofound = i; + ofound = BVAL(i); + break; } - if (ibaud - iclose <= baud_table[i] && - ibaud + iclose >= baud_table[i]) { - /* For the case input == output don't set IBAUD bits - if the user didn't do so */ - if (ofound == i && !ibinput) - ifound = i; -#ifdef IBSHIFT - else { - ifound = i; - termios->c_cflag |= (baud_bits[i] << IBSHIFT); + } + if (!ibinput) { + ifound = 0; + } else { + for (i = 0; i < n_baud_table; i++) { + if (ibaud - iclose <= baud_table[i] && + ibaud + iclose >= baud_table[i]) { + ifound = BVAL(i); + break; } -#endif } - } while (++i < n_baud_table); + }
- /* - * If we found no match then use BOTHER if provided or warn - * the user their platform maintainer needs to wake up if not. - */ -#ifdef BOTHER - if (ofound == -1) - termios->c_cflag |= BOTHER; - /* Set exact input bits only if the input and output differ or the - user already did */ - if (ifound == -1 && (ibaud != obaud || ibinput)) - termios->c_cflag |= (BOTHER << IBSHIFT); -#else - if (ifound == -1 || ofound == -1) - pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n"); -#endif + termios->c_cflag &= ~(CBAUD | (CBAUD << IBSHIFT)); + termios->c_cflag |= ofound | (ifound << IBSHIFT); } EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);