Commit 077746a2 authored by Russell King's avatar Russell King

[SERIAL] Restrict the baud rates returnable from uart_get_baud_rate()

Supply the old termios, along with the max and min acceptable baud
rate to uart_get_baud_rate().  uart_get_baud_rate() will now try to
find a baud rate that satisfies the max and min constraint out of
(requested rate, old rate, 9600 baud).

We remove the code which performed a similar act in uart_get_divisor()
and pass an appropriate min and max baud rate to uart_get_baud_rate()
based on the UART clock rate.
parent 994ee212
...@@ -314,32 +314,39 @@ EXPORT_SYMBOL(uart_update_timeout); ...@@ -314,32 +314,39 @@ EXPORT_SYMBOL(uart_update_timeout);
* uart_get_baud_rate - return baud rate for a particular port * uart_get_baud_rate - return baud rate for a particular port
* @port: uart_port structure describing the port in question. * @port: uart_port structure describing the port in question.
* @termios: desired termios settings. * @termios: desired termios settings.
* @old: old termios (or NULL)
* @min: minimum acceptable baud rate
* @max: maximum acceptable baud rate
* *
* Decode the termios structure into a numeric baud rate, * Decode the termios structure into a numeric baud rate,
* taking account of the magic 38400 baud rate (with spd_* * taking account of the magic 38400 baud rate (with spd_*
* flags), and mapping the %B0 rate to 9600 baud. * flags), and mapping the %B0 rate to 9600 baud.
*/ */
unsigned int unsigned int
uart_get_baud_rate(struct uart_port *port, struct termios *termios) uart_get_baud_rate(struct uart_port *port, struct termios *termios,
struct termios *old, unsigned int min, unsigned int max)
{ {
unsigned int baud = tty_termios_baud_rate(termios); unsigned int try, baud, altbaud = 38400;
/*
* The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
* Die! Die! Die!
*/
if (baud == 38400) {
unsigned int flags = port->flags & UPF_SPD_MASK; unsigned int flags = port->flags & UPF_SPD_MASK;
if (flags == UPF_SPD_HI) if (flags == UPF_SPD_HI)
baud = 57600; altbaud = 57600;
if (flags == UPF_SPD_VHI) if (flags == UPF_SPD_VHI)
baud = 115200; altbaud = 115200;
if (flags == UPF_SPD_SHI) if (flags == UPF_SPD_SHI)
baud = 230400; altbaud = 230400;
if (flags == UPF_SPD_WARP) if (flags == UPF_SPD_WARP)
baud = 460800; altbaud = 460800;
}
for (try = 0; try < 2; try++) {
baud = tty_termios_baud_rate(termios);
/*
* The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
* Die! Die! Die!
*/
if (baud == 38400)
baud = altbaud;
/* /*
* Special case: B0 rate. * Special case: B0 rate.
...@@ -347,7 +354,28 @@ uart_get_baud_rate(struct uart_port *port, struct termios *termios) ...@@ -347,7 +354,28 @@ uart_get_baud_rate(struct uart_port *port, struct termios *termios)
if (baud == 0) if (baud == 0)
baud = 9600; baud = 9600;
if (baud >= min && baud <= max)
return baud; return baud;
/*
* Oops, the quotient was zero. Try again with
* the old baud rate if possible.
*/
termios->c_cflag &= ~CBAUD;
if (old) {
termios->c_cflag |= old->c_cflag & CBAUD;
old = NULL;
continue;
}
/*
* As a last resort, if the quotient is zero,
* default to 9600 bps
*/
termios->c_cflag |= B9600;
}
return 0;
} }
EXPORT_SYMBOL(uart_get_baud_rate); EXPORT_SYMBOL(uart_get_baud_rate);
...@@ -355,16 +383,6 @@ EXPORT_SYMBOL(uart_get_baud_rate); ...@@ -355,16 +383,6 @@ EXPORT_SYMBOL(uart_get_baud_rate);
static inline unsigned int static inline unsigned int
uart_calculate_quot(struct uart_port *port, unsigned int baud) uart_calculate_quot(struct uart_port *port, unsigned int baud)
{ {
unsigned int quot;
/*
* Old custom speed handling.
*/
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor;
else
quot = port->uartclk / (16 * baud);
return quot; return quot;
} }
...@@ -387,34 +405,18 @@ unsigned int ...@@ -387,34 +405,18 @@ unsigned int
uart_get_divisor(struct uart_port *port, struct termios *termios, uart_get_divisor(struct uart_port *port, struct termios *termios,
struct termios *old_termios) struct termios *old_termios)
{ {
unsigned int quot, try; unsigned int quot, baud, max = port->uartclk / 16;
for (try = 0; try < 3; try ++) {
unsigned int baud;
/* Determine divisor based on baud rate */ /* Determine divisor based on baud rate */
baud = uart_get_baud_rate(port, termios); baud = uart_get_baud_rate(port, termios, old_termios, 0, max);
quot = uart_calculate_quot(port, baud);
if (quot)
return quot;
/* /*
* Oops, the quotient was zero. Try again with * Old custom speed handling.
* the old baud rate if possible.
*/
termios->c_cflag &= ~CBAUD;
if (old_termios) {
termios->c_cflag |= old_termios->c_cflag & CBAUD;
old_termios = NULL;
continue;
}
/*
* As a last resort, if the quotient is zero,
* default to 9600 bps
*/ */
termios->c_cflag |= B9600; if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
} quot = port->custom_divisor;
else
quot = port->uartclk / (16 * baud);
return quot; return quot;
} }
......
...@@ -280,8 +280,9 @@ void uart_write_wakeup(struct uart_port *port); ...@@ -280,8 +280,9 @@ void uart_write_wakeup(struct uart_port *port);
*/ */
void uart_update_timeout(struct uart_port *port, unsigned int cflag, void uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int quot); unsigned int quot);
unsigned int uart_get_baud_rate(struct uart_port *port, unsigned int uart_get_baud_rate(struct uart_port *port, struct termios *termios
struct termios *termios); struct termios *old, unsigned int min,
unsigned int max);
unsigned int uart_get_divisor(struct uart_port *port, struct termios *termios, unsigned int uart_get_divisor(struct uart_port *port, struct termios *termios,
struct termios *old_termios); struct termios *old_termios);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment