Commit 581b7bba authored by Russell King's avatar Russell King

[SERIAL] Convert change_speed() to settermios()

Several serial drivers want to obtain the numeric baud rate when
configuring their serial ports.  Currently, two methods are used
to "work around" this inadequacy in the change_speed API:

	baud = tty_get_baud_rate(port->info->tty);

	baud = BAUD_BASE / (16 * quot);

Passing the termios structure down means that we can use 
uart_get_baud_rate() instead.  We can also ensure that the various
termios flags for options we don't support are correctly set.

Lastly, this also provides 8250.c with a clean method for supporting
divisors that are greater than the baud_base.
parent b80f8a3a
......@@ -176,11 +176,11 @@ hardware.
Locking: port_sem taken.
Interrupts: caller dependent.
change_speed(port,cflag,iflag,quot)
settermios(port,termios,oldtermios)
Change the port parameters, including word length, parity, stop
bits. Update read_status_mask and ignore_status_mask to indicate
the types of events we are interested in receiving. Relevant
cflag bits are:
termios->c_cflag bits are:
CSIZE - word size
CSTOPB - 2 stop bits
PARENB - parity enable
......@@ -191,7 +191,7 @@ hardware.
CRTSCTS - if set, enable CTS status change reporting
CLOCAL - if not set, enable modem status change
reporting.
Relevant iflag bits are:
Relevant termios->c_iflag bits are:
INPCK - enable frame and parity error events to be
passed to the TTY layer.
BRKINT
......@@ -278,6 +278,35 @@ hardware.
Locking: none.
Interrupts: caller dependent.
Other functions
---------------
uart_update_timeout(port,cflag,quot)
Update the FIFO drain timeout, port->timeout, according to the
number of bits, parity, stop bits and quotient.
Locking: caller is expected to take port->lock
Interrupts: n/a
uart_get_baud_rate(port,termios)
Return the numeric baud rate for the specified termios, taking
account of the special 38400 baud "kludge". The B0 baud rate
is mapped to 9600 baud.
Locking: caller dependent.
Interrupts: n/a
uart_get_divisor(port,termios,oldtermios)
Return the divsor (baud_base / baud) for the selected baud rate
specified by termios. If the baud rate is out of range, try
the original baud rate specified by oldtermios (if non-NULL).
If that fails, try 9600 baud.
If 38400 baud and custom divisor is selected, return the
custom divisor instead.
Locking: caller dependent.
Interrupts: n/a
Other notes
-----------
......@@ -292,10 +321,3 @@ thus:
struct uart_port port;
int my_stuff;
};
Todo
----
Please see the BUGS file in CVS at
http://cvs.arm.linux.org.uk/cgi/viewcvs.cgi/serial/BUGS
......@@ -233,12 +233,29 @@ static void serial21285_shutdown(struct uart_port *port)
}
static void
serial21285_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
serial21285_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int h_lcr;
unsigned long flags;
unsigned int quot, h_lcr;
/*
* We don't support modem control lines.
*/
termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
termios->c_cflag |= CLOCAL;
/*
* We don't support BREAK character recognition.
*/
termios->c_iflag &= ~(IGNBRK | BRKINT);
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
switch (cflag & CSIZE) {
switch (termios->c_cflag & CSIZE) {
case CS5:
h_lcr = 0x00;
break;
......@@ -253,34 +270,44 @@ serial21285_change_speed(struct uart_port *port, unsigned int cflag,
break;
}
if (cflag & CSTOPB)
if (termios->c_cflag & CSTOPB)
h_lcr |= H_UBRLCR_STOPB;
if (cflag & PARENB) {
if (termios->c_cflag & PARENB) {
h_lcr |= H_UBRLCR_PARENB;
if (!(cflag & PARODD))
if (!(termios->c_cflag & PARODD))
h_lcr |= H_UBRLCR_PAREVN;
}
if (port->fifosize)
h_lcr |= H_UBRLCR_FIFO;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
/*
* Which character status flags are we interested in?
*/
port->read_status_mask = RXSTAT_OVERRUN;
if (iflag & INPCK)
if (termios->c_iflag & INPCK)
port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
/*
* Characters to ignore
* Which character status flags should we ignore?
*/
port->ignore_status_mask = 0;
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
if (iflag & IGNBRK && iflag & IGNPAR)
if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RXSTAT_OVERRUN;
/*
* Ignore all characters if CREAD is not set.
*/
if ((cflag & CREAD) == 0)
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= RXSTAT_DUMMY_READ;
quot -= 1;
......@@ -290,6 +317,8 @@ serial21285_change_speed(struct uart_port *port, unsigned int cflag,
*CSR_M_UBRLCR = (quot >> 8) & 0x0f;
*CSR_H_UBRLCR = h_lcr;
*CSR_UARTCON = 1;
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *serial21285_type(struct uart_port *port)
......@@ -340,7 +369,7 @@ static struct uart_ops serial21285_ops = {
.break_ctl = serial21285_break_ctl,
.startup = serial21285_startup,
.shutdown = serial21285_shutdown,
.change_speed = serial21285_change_speed,
.settermios = serial21285_settermios,
.type = serial21285_type,
.release_port = serial21285_release_port,
.request_port = serial21285_request_port,
......
......@@ -1174,7 +1174,7 @@ static int serial8250_startup(struct uart_port *port)
/*
* Clear the FIFO buffers and disable them.
* (they will be reeanbled in change_speed())
* (they will be reeanbled in settermios())
*/
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
......@@ -1241,7 +1241,7 @@ static int serial8250_startup(struct uart_port *port)
/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via change_speed(), which will be occuring imminently
* are set via settermios(), which will be occuring imminently
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
......@@ -1319,14 +1319,15 @@ static void serial8250_shutdown(struct uart_port *port)
}
static void
serial8250_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
serial8250_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int quot;
switch (cflag & CSIZE) {
switch (termios->c_cflag & CSIZE) {
case CS5:
cval = 0x00;
break;
......@@ -1342,17 +1343,22 @@ serial8250_change_speed(struct uart_port *port, unsigned int cflag,
break;
}
if (cflag & CSTOPB)
if (termios->c_cflag & CSTOPB)
cval |= 0x04;
if (cflag & PARENB)
if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(cflag & PARODD))
if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
if (cflag & CMSPAR)
if (termios->c_cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
/*
* Work around a bug in the Oxford Semiconductor 952 rev B
* chip which causes it to seriously miscalculate baud rates
......@@ -1375,52 +1381,58 @@ serial8250_change_speed(struct uart_port *port, unsigned int cflag,
if (up->port.type == PORT_16750)
fcr |= UART_FCR7_64BYTE;
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
spin_lock_irqsave(&up->port.lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (iflag & INPCK)
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (iflag & (BRKINT | PARMRK))
if (termios->c_iflag & (BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/*
* Characteres to ignore
*/
up->port.ignore_status_mask = 0;
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
if (iflag & IGNBRK) {
if (termios->c_iflag & IGNBRK) {
up->port.ignore_status_mask |= UART_LSR_BI;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_OE;
}
/*
* ignore all characters if CREAD is not set
*/
if ((cflag & CREAD) == 0)
if ((termios->c_cflag & CREAD) == 0)
up->port.ignore_status_mask |= UART_LSR_DR;
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
spin_lock_irqsave(&up->port.lock, flags);
/*
* CTS flow control flag and modem status interrupts
*/
up->ier &= ~UART_IER_MSI;
if (UART_ENABLE_MS(&up->port, cflag))
if (UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
if (uart_config[up->port.type].flags & UART_STARTECH) {
serial_outp(up, UART_LCR, 0xBF);
serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
serial_outp(up, UART_EFR,
termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
}
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
......@@ -1728,7 +1740,7 @@ static struct uart_ops serial8250_pops = {
.break_ctl = serial8250_break_ctl,
.startup = serial8250_startup,
.shutdown = serial8250_shutdown,
.change_speed = serial8250_change_speed,
.settermios = serial8250_settermios,
.pm = serial8250_pm,
.type = serial8250_type,
.release_port = serial8250_release_port,
......
......@@ -403,14 +403,19 @@ static void ambauart_shutdown(struct uart_port *port)
}
static void
ambauart_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
ambauart_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int quot;
/* byte size and parity */
switch (cflag & CSIZE) {
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr_h = AMBA_UARTLCR_H_WLEN_5;
break;
......@@ -424,49 +429,55 @@ ambauart_change_speed(struct uart_port *port, unsigned int cflag,
lcr_h = AMBA_UARTLCR_H_WLEN_8;
break;
}
if (cflag & CSTOPB)
if (termios->c_cflag & CSTOPB)
lcr_h |= AMBA_UARTLCR_H_STP2;
if (cflag & PARENB) {
if (termios->c_cflag & PARENB) {
lcr_h |= AMBA_UARTLCR_H_PEN;
if (!(cflag & PARODD))
if (!(termios->c_cflag & PARODD))
lcr_h |= AMBA_UARTLCR_H_EPS;
}
if (port->fifosize > 1)
lcr_h |= AMBA_UARTLCR_H_FEN;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
port->read_status_mask = AMBA_UARTRSR_OE;
if (iflag & INPCK)
if (termios->c_iflag & INPCK)
port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
if (iflag & (BRKINT | PARMRK))
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= AMBA_UARTRSR_BE;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
if (iflag & IGNBRK) {
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= AMBA_UARTRSR_BE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= AMBA_UARTRSR_OE;
}
/*
* Ignore all characters if CREAD is not set.
*/
if ((cflag & CREAD) == 0)
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= UART_DUMMY_RSR_RX;
/* first, disable everything */
spin_lock_irqsave(&port->lock, flags);
old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE;
if (UART_ENABLE_MS(port, cflag))
if (UART_ENABLE_MS(port, termios->c_cflag))
old_cr |= AMBA_UARTCR_MSIE;
UART_PUT_CR(port, 0);
......@@ -546,7 +557,7 @@ static struct uart_ops amba_pops = {
.break_ctl = ambauart_break_ctl,
.startup = ambauart_startup,
.shutdown = ambauart_shutdown,
.change_speed = ambauart_change_speed,
.settermios = ambauart_settermios,
.type = ambauart_type,
.release_port = ambauart_release_port,
.request_port = ambauart_request_port,
......
......@@ -283,13 +283,36 @@ static void anakin_shutdown(struct uart_port *port)
}
static void
anakin_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
anakin_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int flags;
unsigned long flags;
unsigned int quot;
/*
* We don't support parity, stop bits, or anything other
* than 8 bits, so clear these termios flags.
*/
termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CREAD);
termios->c_cflag |= CS8;
/*
* We don't appear to support any error conditions either.
*/
termios->c_iflag &= ~(INPCK | IGNPAR | IGNBRK | BRKINT);
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
spin_lock_irqsave(&port->lock, flags);
while (!(anakin_in(port, 0x10) & TXEMPTY));
uart_update_timeout(port, termios->c_cflag, quot);
while (!(anakin_in(port, 0x10) & TXEMPTY))
barrier();
anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER)
| (quot << 3));
......@@ -314,7 +337,7 @@ static struct uart_ops anakin_pops = {
.break_ctl = anakin_break_ctl,
.startup = anakin_startup,
.shutdown = anakin_shutdown,
.change_speed = anakin_change_speed,
.settermios = anakin_settermios,
.type = anakin_type,
};
......
......@@ -317,14 +317,23 @@ static void clps711xuart_shutdown(struct uart_port *port)
}
static void
clps711xuart_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
clps711xuart_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int ubrlcr;
unsigned int ubrlcr, quot;
unsigned long flags;
/* byte size and parity */
switch (cflag & CSIZE) {
/*
* We don't implement CREAD.
*/
termios->c_cflag |= CREAD;
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
switch (termios->c_cflag & CSIZE) {
case CS5:
ubrlcr = UBRLCR_WRDLEN5;
break;
......@@ -338,40 +347,44 @@ clps711xuart_change_speed(struct uart_port *port, unsigned int cflag,
ubrlcr = UBRLCR_WRDLEN8;
break;
}
if (cflag & CSTOPB)
if (termios->c_cflag & CSTOPB)
ubrlcr |= UBRLCR_XSTOP;
if (cflag & PARENB) {
if (termios->c_cflag & PARENB) {
ubrlcr |= UBRLCR_PRTEN;
if (!(cflag & PARODD))
if (!(termios->c_cflag & PARODD))
ubrlcr |= UBRLCR_EVENPRT;
}
if (port->fifosize > 1)
ubrlcr |= UBRLCR_FIFOEN;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
port->read_status_mask = UARTDR_OVERR;
if (iflag & INPCK)
if (termios->c_iflag & INPCK)
port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
if (iflag & IGNBRK) {
if (termios->c_iflag & IGNBRK) {
/*
* If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support).
*/
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_OVERR;
}
quot -= 1;
/* first, disable everything */
spin_lock_irqsave(&port->lock, flags);
clps_writel(ubrlcr | quot, UBRLCR(port));
spin_unlock_irqrestore(&port->lock, flags);
......@@ -411,7 +424,7 @@ static struct uart_ops clps711x_pops = {
.break_ctl = clps711xuart_break_ctl,
.startup = clps711xuart_startup,
.shutdown = clps711xuart_shutdown,
.change_speed = clps711xuart_change_speed,
.settermios = clps711xuart_settermios,
.type = clps711xuart_type,
.config_port = clps711xuart_config_port,
.release_port = clps711xuart_release_port,
......
......@@ -451,10 +451,7 @@ uart_change_speed(struct uart_info *info, struct termios *old_termios)
else
info->flags |= UIF_CHECK_CD;
quot = uart_get_divisor(port, termios, old_termios);
uart_update_timeout(port, termios->c_cflag, quot);
port->ops->change_speed(port, termios->c_cflag, termios->c_iflag, quot);
port->ops->settermios(port, termios, old_termios);
}
static inline void
......@@ -1857,10 +1854,13 @@ int __init
uart_set_options(struct uart_port *port, struct console *co,
int baud, int parity, int bits, int flow)
{
unsigned int cflag = CREAD | HUPCL | CLOCAL;
unsigned int quot;
struct termios termios;
int i;
memset(&termios, 0, sizeof(struct termios));
termios.c_cflag = CREAD | HUPCL | CLOCAL;
/*
* Construct a cflag setting.
*/
......@@ -1868,28 +1868,27 @@ uart_set_options(struct uart_port *port, struct console *co,
if (baud_rates[i].rate <= baud)
break;
cflag |= baud_rates[i].cflag;
termios.c_cflag |= baud_rates[i].cflag;
if (bits == 7)
cflag |= CS7;
termios.c_cflag |= CS7;
else
cflag |= CS8;
termios.c_cflag |= CS8;
switch (parity) {
case 'o': case 'O':
cflag |= PARODD;
termios.c_cflag |= PARODD;
/*fall through*/
case 'e': case 'E':
cflag |= PARENB;
termios.c_cflag |= PARENB;
break;
}
if (flow == 'r')
cflag |= CRTSCTS;
termios.c_cflag |= CRTSCTS;
co->cflag = cflag;
quot = (port->uartclk / (16 * baud));
port->ops->change_speed(port, cflag, 0, quot);
port->ops->settermios(port, &termios, NULL);
co->cflag = termios.c_cflag;
return 0;
}
......
......@@ -268,17 +268,16 @@ static void mux_shutdown(struct uart_port *port)
}
/**
* mux_change_speed - Chane port parameters.
* mux_settermios - Chane port parameters.
* @port: Ptr to the uart_port.
* @cflag: character flags.
* @iflag: interrupt flags.
* @quot:
* @termios: new termios settings.
* @old: old termios settings.
*
* The Serial Mux does not support this function.
*/
static void
mux_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
mux_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
}
......@@ -388,7 +387,7 @@ static struct uart_ops mux_pops = {
.break_ctl = mux_break_ctl,
.startup = mux_startup,
.shutdown = mux_shutdown,
.change_speed = mux_change_speed,
.settermios = mux_settermios,
.type = mux_type,
.release_port = mux_release_port,
.request_port = mux_request_port,
......
......@@ -440,15 +440,13 @@ static void nb85e_uart_shutdown (struct uart_port *port)
}
static void
nb85e_uart_change_speed (struct uart_port *port, unsigned cflags,
unsigned iflag, unsigned quot)
nb85e_uart_settermios (struct uart_port *port, struct termios *termios,
struct termios *old)
{
/* The serial framework doesn't give us the baud rate directly, but
insists on calculating a `quotient' from it, and giving us that
instead. Get the real baud rate from the tty code instead. */
int baud = tty_get_baud_rate (port->info->tty);
/* FIXME: Which termios flags does this driver support? --rmk */
nb85e_uart_configure (port->line, cflags, baud);
nb85e_uart_configure (port->line, termios->c_cflags,
uart_get_baud_rate(port, termios));
}
static const char *nb85e_uart_type (struct uart_port *port)
......@@ -483,7 +481,7 @@ static struct uart_ops nb85e_uart_ops = {
.break_ctl = nb85e_uart_break_ctl,
.startup = nb85e_uart_startup,
.shutdown = nb85e_uart_shutdown,
.change_speed = nb85e_uart_change_speed,
.settermios = nb85e_uart_settermios,
.type = nb85e_uart_type,
.release_port = nb85e_uart_nop,
.request_port = nb85e_uart_success,
......
......@@ -436,36 +436,50 @@ static void sa1100_shutdown(struct uart_port *port)
}
static void
sa1100_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
sa1100_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
unsigned int utcr0, old_utcr3;
unsigned int utcr0, old_utcr3, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
/* byte size and parity */
switch (cflag & CSIZE) {
case CS7:
utcr0 = 0;
break;
default:
utcr0 = UTCR0_DSS;
break;
/*
* We only support CS7 and CS8.
*/
while ((termios->c_cflag & CSIZE) != CS7 ||
(termios->c_cflag & CSIZE) != CS8) {
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= old_csize;
old_csize = CS8;
}
if (cflag & CSTOPB)
if ((termios->c_cflag & CSIZE) == CS8)
utcr0 = UTCR0_DSS;
else
utcr0 = 0;
if (termios->c_cflag & CSTOPB)
utcr0 |= UTCR0_SBS;
if (cflag & PARENB) {
if (termios->c_cflag & PARENB) {
utcr0 |= UTCR0_PE;
if (!(cflag & PARODD))
if (!(termios->c_cflag & PARODD))
utcr0 |= UTCR0_OES;
}
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
spin_lock_irqsave(&sport->port.lock, flags);
sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
if (iflag & INPCK)
if (termios->c_iflag & INPCK)
sport->port.read_status_mask |=
UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
if (iflag & (BRKINT | PARMRK))
if (termios->c_iflag & (BRKINT | PARMRK))
sport->port.read_status_mask |=
UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
......@@ -473,29 +487,36 @@ sa1100_change_speed(struct uart_port *port, unsigned int cflag,
* Characters to ignore
*/
sport->port.ignore_status_mask = 0;
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |=
UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
if (iflag & IGNBRK) {
if (termios->c_iflag & IGNBRK) {
sport->port.ignore_status_mask |=
UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |=
UTSR1_TO_SM(UTSR1_ROR);
}
del_timer_sync(&sport->timer);
/* first, disable interrupts and drain transmitter */
spin_lock_irqsave(&sport->port.lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
/*
* disable interrupts and drain transmitter
*/
old_utcr3 = UART_GET_UTCR3(sport);
UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
while (UART_GET_UTSR1(sport) & UTSR1_TBY);
while (UART_GET_UTSR1(sport) & UTSR1_TBY)
barrier();
/* then, disable everything */
UART_PUT_UTCR3(sport, 0);
......@@ -512,7 +533,7 @@ sa1100_change_speed(struct uart_port *port, unsigned int cflag,
UART_PUT_UTCR3(sport, old_utcr3);
if (UART_ENABLE_MS(&sport->port, cflag))
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
sa1100_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock, flags);
......@@ -597,7 +618,7 @@ static struct uart_ops sa1100_pops = {
.break_ctl = sa1100_break_ctl,
.startup = sa1100_startup,
.shutdown = sa1100_shutdown,
.change_speed = sa1100_change_speed,
.settermios = sa1100_settermios,
.type = sa1100_type,
.release_port = sa1100_release_port,
.request_port = sa1100_request_port,
......
......@@ -777,20 +777,15 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
}
/* port->lock is not held. */
static void sunsab_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
static void sunsab_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags;
int baud;
int baud = uart_get_baud_rate(port, termios);
spin_lock_irqsave(&up->port.lock, flags);
/* Undo what generic UART core did. */
baud = (SAB_BASE_BAUD / (quot * 16));
sunsab_convert_to_sab(up, cflag, iflag, baud);
sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud);
spin_unlock_irqrestore(&up->port.lock, flags);
}
......@@ -829,7 +824,7 @@ static struct uart_ops sunsab_pops = {
.break_ctl = sunsab_break_ctl,
.startup = sunsab_startup,
.shutdown = sunsab_shutdown,
.change_speed = sunsab_change_speed,
.settermios = sunsab_settermios,
.type = sunsab_type,
.release_port = sunsab_release_port,
.request_port = sunsab_request_port,
......
......@@ -660,7 +660,7 @@ static int sunsu_startup(struct uart_port *port)
/*
* Clear the FIFO buffers and disable them.
* (they will be reeanbled in change_speed())
* (they will be reeanbled in settermios())
*/
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
......@@ -714,7 +714,7 @@ static int sunsu_startup(struct uart_port *port)
/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via change_speed(), which will be occuring imminently
* are set via settermios(), which will be occuring imminently
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
......@@ -844,6 +844,17 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
if (up->port.type == PORT_16750)
fcr |= UART_FCR7_64BYTE;
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
spin_lock_irqsave(&up->port.lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, cflag, quot);
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
......@@ -879,11 +890,6 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
if (UART_ENABLE_MS(&up->port, cflag))
up->ier |= UART_IER_MSI;
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
spin_lock_irqsave(&up->port.lock, flags);
serial_out(up, UART_IER, up->ier);
if (uart_config[up->port.type].flags & UART_STARTECH) {
......@@ -910,6 +916,20 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
spin_unlock_irqrestore(&up->port.lock, flags);
}
static void
sunsu_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int quot;
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot);
}
static void sunsu_release_port(struct uart_port *port)
{
}
......@@ -960,7 +980,7 @@ static struct uart_ops sunsu_pops = {
.break_ctl = sunsu_break_ctl,
.startup = sunsu_startup,
.shutdown = sunsu_shutdown,
.change_speed = sunsu_change_speed,
.settermios = sunsu_settermios,
.type = sunsu_type,
.release_port = sunsu_release_port,
.request_port = sunsu_request_port,
......
......@@ -917,26 +917,27 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
/* The port lock is not held. */
static void
sunzilog_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
sunzilog_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
unsigned long flags;
int baud, brg;
baud = uart_get_baud_rate(port, termios);
spin_lock_irqsave(&up->port.lock, flags);
baud = (ZS_CLOCK / (quot * 16));
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
sunzilog_convert_to_zs(up, cflag, iflag, brg);
sunzilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
if (UART_ENABLE_MS(&up->port, cflag))
if (UART_ENABLE_MS(&up->port, termios->c_cflag))
up->flags |= SUNZILOG_FLAG_MODEM_STATUS;
else
up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS;
up->cflag = cflag;
up->cflag = termios->c_cflag;
sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
......@@ -982,7 +983,7 @@ static struct uart_ops sunzilog_pops = {
.break_ctl = sunzilog_break_ctl,
.startup = sunzilog_startup,
.shutdown = sunzilog_shutdown,
.change_speed = sunzilog_change_speed,
.settermios = sunzilog_settermios,
.type = sunzilog_type,
.release_port = sunzilog_release_port,
.request_port = sunzilog_request_port,
......
......@@ -314,14 +314,24 @@ static void uart00_break_ctl(struct uart_port *port, int break_state)
}
static void
uart00_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
uart00_settermios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int uart_mc, old_ies;
unsigned int uart_mc, old_ies, quot;
unsigned long flags;
/*
* We don't support CREAD (yet)
*/
termios->c_cflag |= CREAD;
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
/* byte size and parity */
switch (cflag & CSIZE) {
switch (termios->c_cflag & CSIZE) {
case CS5:
uart_mc = UART_MC_CLS_CHARLEN_5;
break;
......@@ -335,41 +345,47 @@ uart00_change_speed(struct uart_port *port, unsigned int cflag,
uart_mc = UART_MC_CLS_CHARLEN_8;
break;
}
if (cflag & CSTOPB)
if (termios->c_cflag & CSTOPB)
uart_mc|= UART_MC_ST_TWO;
if (cflag & PARENB) {
if (termios->c_cflag & PARENB) {
uart_mc |= UART_MC_PE_MSK;
if (!(cflag & PARODD))
if (!(termios->c_cflag & PARODD))
uart_mc |= UART_MC_EP_MSK;
}
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
port->read_status_mask = UART_RDS_OE_MSK;
if (iflag & INPCK)
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
if (iflag & (BRKINT | PARMRK))
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= UART_RDS_BI_MSK;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
if (iflag & IGNBRK) {
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= UART_RDS_BI_MSK;
/*
* If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support).
*/
if (iflag & IGNPAR)
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_RDS_OE_MSK;
}
/* first, disable everything */
spin_lock_irqsave(&port->lock, flags);
old_ies = UART_GET_IES(port);
if (UART_ENABLE_MS(port, cflag))
if (UART_ENABLE_MS(port, termios->c_cflag))
old_ies |= UART_IES_ME_MSK;
/* Set baud rate */
......@@ -495,7 +511,7 @@ static struct uart_ops uart00_pops = {
.break_ctl = uart00_break_ctl,
.startup = uart00_startup,
.shutdown = uart00_shutdown,
.change_speed = uart00_change_speed,
.settermios = uart00_settermios,
.type = uart00_type,
.release_port = uart00_release_port,
.request_port = uart00_request_port,
......
......@@ -86,8 +86,8 @@ struct uart_ops {
void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *);
void (*shutdown)(struct uart_port *);
void (*change_speed)(struct uart_port *, unsigned int cflag,
unsigned int iflag, unsigned int quot);
void (*settermios)(struct uart_port *, struct termios *new,
struct termios *old);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state);
......
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