Commit a0e6cf38 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 456cb076 077746a2
...@@ -176,11 +176,11 @@ hardware. ...@@ -176,11 +176,11 @@ hardware.
Locking: port_sem taken. Locking: port_sem taken.
Interrupts: caller dependent. Interrupts: caller dependent.
change_speed(port,cflag,iflag,quot) set_termios(port,termios,oldtermios)
Change the port parameters, including word length, parity, stop Change the port parameters, including word length, parity, stop
bits. Update read_status_mask and ignore_status_mask to indicate bits. Update read_status_mask and ignore_status_mask to indicate
the types of events we are interested in receiving. Relevant the types of events we are interested in receiving. Relevant
cflag bits are: termios->c_cflag bits are:
CSIZE - word size CSIZE - word size
CSTOPB - 2 stop bits CSTOPB - 2 stop bits
PARENB - parity enable PARENB - parity enable
...@@ -191,7 +191,7 @@ hardware. ...@@ -191,7 +191,7 @@ hardware.
CRTSCTS - if set, enable CTS status change reporting CRTSCTS - if set, enable CTS status change reporting
CLOCAL - if not set, enable modem status change CLOCAL - if not set, enable modem status change
reporting. reporting.
Relevant iflag bits are: Relevant termios->c_iflag bits are:
INPCK - enable frame and parity error events to be INPCK - enable frame and parity error events to be
passed to the TTY layer. passed to the TTY layer.
BRKINT BRKINT
...@@ -278,6 +278,35 @@ hardware. ...@@ -278,6 +278,35 @@ hardware.
Locking: none. Locking: none.
Interrupts: caller dependent. 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 Other notes
----------- -----------
...@@ -292,10 +321,3 @@ thus: ...@@ -292,10 +321,3 @@ thus:
struct uart_port port; struct uart_port port;
int my_stuff; 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) ...@@ -233,12 +233,29 @@ static void serial21285_shutdown(struct uart_port *port)
} }
static void static void
serial21285_change_speed(struct uart_port *port, unsigned int cflag, serial21285_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) 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: case CS5:
h_lcr = 0x00; h_lcr = 0x00;
break; break;
...@@ -253,34 +270,44 @@ serial21285_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -253,34 +270,44 @@ serial21285_change_speed(struct uart_port *port, unsigned int cflag,
break; break;
} }
if (cflag & CSTOPB) if (termios->c_cflag & CSTOPB)
h_lcr |= H_UBRLCR_STOPB; h_lcr |= H_UBRLCR_STOPB;
if (cflag & PARENB) { if (termios->c_cflag & PARENB) {
h_lcr |= H_UBRLCR_PARENB; h_lcr |= H_UBRLCR_PARENB;
if (!(cflag & PARODD)) if (!(termios->c_cflag & PARODD))
h_lcr |= H_UBRLCR_PAREVN; h_lcr |= H_UBRLCR_PAREVN;
} }
if (port->fifosize) if (port->fifosize)
h_lcr |= H_UBRLCR_FIFO; 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; port->read_status_mask = RXSTAT_OVERRUN;
if (iflag & INPCK) if (termios->c_iflag & INPCK)
port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
/* /*
* Characters to ignore * Which character status flags should we ignore?
*/ */
port->ignore_status_mask = 0; port->ignore_status_mask = 0;
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; 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; port->ignore_status_mask |= RXSTAT_OVERRUN;
/* /*
* Ignore all characters if CREAD is not set. * 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; port->ignore_status_mask |= RXSTAT_DUMMY_READ;
quot -= 1; quot -= 1;
...@@ -290,6 +317,8 @@ serial21285_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -290,6 +317,8 @@ serial21285_change_speed(struct uart_port *port, unsigned int cflag,
*CSR_M_UBRLCR = (quot >> 8) & 0x0f; *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
*CSR_H_UBRLCR = h_lcr; *CSR_H_UBRLCR = h_lcr;
*CSR_UARTCON = 1; *CSR_UARTCON = 1;
spin_unlock_irqrestore(&port->lock, flags);
} }
static const char *serial21285_type(struct uart_port *port) static const char *serial21285_type(struct uart_port *port)
...@@ -340,7 +369,7 @@ static struct uart_ops serial21285_ops = { ...@@ -340,7 +369,7 @@ static struct uart_ops serial21285_ops = {
.break_ctl = serial21285_break_ctl, .break_ctl = serial21285_break_ctl,
.startup = serial21285_startup, .startup = serial21285_startup,
.shutdown = serial21285_shutdown, .shutdown = serial21285_shutdown,
.change_speed = serial21285_change_speed, .set_termios = serial21285_set_termios,
.type = serial21285_type, .type = serial21285_type,
.release_port = serial21285_release_port, .release_port = serial21285_release_port,
.request_port = serial21285_request_port, .request_port = serial21285_request_port,
......
...@@ -1174,7 +1174,7 @@ static int serial8250_startup(struct uart_port *port) ...@@ -1174,7 +1174,7 @@ static int serial8250_startup(struct uart_port *port)
/* /*
* Clear the FIFO buffers and disable them. * Clear the FIFO buffers and disable them.
* (they will be reeanbled in change_speed()) * (they will be reeanbled in set_termios())
*/ */
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) { if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
...@@ -1241,7 +1241,7 @@ static int serial8250_startup(struct uart_port *port) ...@@ -1241,7 +1241,7 @@ static int serial8250_startup(struct uart_port *port)
/* /*
* Finally, enable interrupts. Note: Modem status interrupts * Finally, enable interrupts. Note: Modem status interrupts
* are set via change_speed(), which will be occuring imminently * are set via set_termios(), which will be occuring imminently
* anyway, so we don't enable them here. * anyway, so we don't enable them here.
*/ */
up->ier = UART_IER_RLSI | UART_IER_RDI; up->ier = UART_IER_RLSI | UART_IER_RDI;
...@@ -1319,14 +1319,15 @@ static void serial8250_shutdown(struct uart_port *port) ...@@ -1319,14 +1319,15 @@ static void serial8250_shutdown(struct uart_port *port)
} }
static void static void
serial8250_change_speed(struct uart_port *port, unsigned int cflag, serial8250_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
struct uart_8250_port *up = (struct uart_8250_port *)port; struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0; unsigned char cval, fcr = 0;
unsigned long flags; unsigned long flags;
unsigned int quot;
switch (cflag & CSIZE) { switch (termios->c_cflag & CSIZE) {
case CS5: case CS5:
cval = 0x00; cval = 0x00;
break; break;
...@@ -1342,17 +1343,22 @@ serial8250_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -1342,17 +1343,22 @@ serial8250_change_speed(struct uart_port *port, unsigned int cflag,
break; break;
} }
if (cflag & CSTOPB) if (termios->c_cflag & CSTOPB)
cval |= 0x04; cval |= 0x04;
if (cflag & PARENB) if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY; cval |= UART_LCR_PARITY;
if (!(cflag & PARODD)) if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR; cval |= UART_LCR_EPAR;
#ifdef CMSPAR #ifdef CMSPAR
if (cflag & CMSPAR) if (termios->c_cflag & CMSPAR)
cval |= UART_LCR_SPAR; cval |= UART_LCR_SPAR;
#endif #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 * Work around a bug in the Oxford Semiconductor 952 rev B
* chip which causes it to seriously miscalculate baud rates * chip which causes it to seriously miscalculate baud rates
...@@ -1375,52 +1381,58 @@ serial8250_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -1375,52 +1381,58 @@ serial8250_change_speed(struct uart_port *port, unsigned int cflag,
if (up->port.type == PORT_16750) if (up->port.type == PORT_16750)
fcr |= UART_FCR7_64BYTE; 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; 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; 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; up->port.read_status_mask |= UART_LSR_BI;
/* /*
* Characteres to ignore * Characteres to ignore
*/ */
up->port.ignore_status_mask = 0; 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; 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; up->port.ignore_status_mask |= UART_LSR_BI;
/* /*
* If we're ignoring parity and break indicators, * If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support). * ignore overruns too (for real raw support).
*/ */
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_OE; up->port.ignore_status_mask |= UART_LSR_OE;
} }
/* /*
* ignore all characters if CREAD is not set * 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; 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 * CTS flow control flag and modem status interrupts
*/ */
up->ier &= ~UART_IER_MSI; 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; up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier); serial_out(up, UART_IER, up->ier);
if (uart_config[up->port.type].flags & UART_STARTECH) { if (uart_config[up->port.type].flags & UART_STARTECH) {
serial_outp(up, UART_LCR, 0xBF); 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_LCR, cval | UART_LCR_DLAB);/* set DLAB */
serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
...@@ -1728,7 +1740,7 @@ static struct uart_ops serial8250_pops = { ...@@ -1728,7 +1740,7 @@ static struct uart_ops serial8250_pops = {
.break_ctl = serial8250_break_ctl, .break_ctl = serial8250_break_ctl,
.startup = serial8250_startup, .startup = serial8250_startup,
.shutdown = serial8250_shutdown, .shutdown = serial8250_shutdown,
.change_speed = serial8250_change_speed, .set_termios = serial8250_set_termios,
.pm = serial8250_pm, .pm = serial8250_pm,
.type = serial8250_type, .type = serial8250_type,
.release_port = serial8250_release_port, .release_port = serial8250_release_port,
......
...@@ -403,14 +403,19 @@ static void ambauart_shutdown(struct uart_port *port) ...@@ -403,14 +403,19 @@ static void ambauart_shutdown(struct uart_port *port)
} }
static void static void
ambauart_change_speed(struct uart_port *port, unsigned int cflag, ambauart_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
unsigned int lcr_h, old_cr; unsigned int lcr_h, old_cr;
unsigned long flags; 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: case CS5:
lcr_h = AMBA_UARTLCR_H_WLEN_5; lcr_h = AMBA_UARTLCR_H_WLEN_5;
break; break;
...@@ -424,49 +429,55 @@ ambauart_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -424,49 +429,55 @@ ambauart_change_speed(struct uart_port *port, unsigned int cflag,
lcr_h = AMBA_UARTLCR_H_WLEN_8; lcr_h = AMBA_UARTLCR_H_WLEN_8;
break; break;
} }
if (cflag & CSTOPB) if (termios->c_cflag & CSTOPB)
lcr_h |= AMBA_UARTLCR_H_STP2; lcr_h |= AMBA_UARTLCR_H_STP2;
if (cflag & PARENB) { if (termios->c_cflag & PARENB) {
lcr_h |= AMBA_UARTLCR_H_PEN; lcr_h |= AMBA_UARTLCR_H_PEN;
if (!(cflag & PARODD)) if (!(termios->c_cflag & PARODD))
lcr_h |= AMBA_UARTLCR_H_EPS; lcr_h |= AMBA_UARTLCR_H_EPS;
} }
if (port->fifosize > 1) if (port->fifosize > 1)
lcr_h |= AMBA_UARTLCR_H_FEN; 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; 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; 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; port->read_status_mask |= AMBA_UARTRSR_BE;
/* /*
* Characters to ignore * Characters to ignore
*/ */
port->ignore_status_mask = 0; port->ignore_status_mask = 0;
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; 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; port->ignore_status_mask |= AMBA_UARTRSR_BE;
/* /*
* If we're ignoring parity and break indicators, * If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support). * ignore overruns too (for real raw support).
*/ */
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= AMBA_UARTRSR_OE; port->ignore_status_mask |= AMBA_UARTRSR_OE;
} }
/* /*
* Ignore all characters if CREAD is not set. * 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; port->ignore_status_mask |= UART_DUMMY_RSR_RX;
/* first, disable everything */ /* first, disable everything */
spin_lock_irqsave(&port->lock, flags);
old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE; 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; old_cr |= AMBA_UARTCR_MSIE;
UART_PUT_CR(port, 0); UART_PUT_CR(port, 0);
...@@ -546,7 +557,7 @@ static struct uart_ops amba_pops = { ...@@ -546,7 +557,7 @@ static struct uart_ops amba_pops = {
.break_ctl = ambauart_break_ctl, .break_ctl = ambauart_break_ctl,
.startup = ambauart_startup, .startup = ambauart_startup,
.shutdown = ambauart_shutdown, .shutdown = ambauart_shutdown,
.change_speed = ambauart_change_speed, .set_termios = ambauart_set_termios,
.type = ambauart_type, .type = ambauart_type,
.release_port = ambauart_release_port, .release_port = ambauart_release_port,
.request_port = ambauart_request_port, .request_port = ambauart_request_port,
......
...@@ -283,13 +283,36 @@ static void anakin_shutdown(struct uart_port *port) ...@@ -283,13 +283,36 @@ static void anakin_shutdown(struct uart_port *port)
} }
static void static void
anakin_change_speed(struct uart_port *port, unsigned int cflag, anakin_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) 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); 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) anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER)
| (quot << 3)); | (quot << 3));
...@@ -314,7 +337,7 @@ static struct uart_ops anakin_pops = { ...@@ -314,7 +337,7 @@ static struct uart_ops anakin_pops = {
.break_ctl = anakin_break_ctl, .break_ctl = anakin_break_ctl,
.startup = anakin_startup, .startup = anakin_startup,
.shutdown = anakin_shutdown, .shutdown = anakin_shutdown,
.change_speed = anakin_change_speed, .set_termios = anakin_set_termios,
.type = anakin_type, .type = anakin_type,
}; };
......
...@@ -317,14 +317,23 @@ static void clps711xuart_shutdown(struct uart_port *port) ...@@ -317,14 +317,23 @@ static void clps711xuart_shutdown(struct uart_port *port)
} }
static void static void
clps711xuart_change_speed(struct uart_port *port, unsigned int cflag, clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
unsigned int ubrlcr; unsigned int ubrlcr, quot;
unsigned long flags; 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: case CS5:
ubrlcr = UBRLCR_WRDLEN5; ubrlcr = UBRLCR_WRDLEN5;
break; break;
...@@ -338,40 +347,44 @@ clps711xuart_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -338,40 +347,44 @@ clps711xuart_change_speed(struct uart_port *port, unsigned int cflag,
ubrlcr = UBRLCR_WRDLEN8; ubrlcr = UBRLCR_WRDLEN8;
break; break;
} }
if (cflag & CSTOPB) if (termios->c_cflag & CSTOPB)
ubrlcr |= UBRLCR_XSTOP; ubrlcr |= UBRLCR_XSTOP;
if (cflag & PARENB) { if (termios->c_cflag & PARENB) {
ubrlcr |= UBRLCR_PRTEN; ubrlcr |= UBRLCR_PRTEN;
if (!(cflag & PARODD)) if (!(termios->c_cflag & PARODD))
ubrlcr |= UBRLCR_EVENPRT; ubrlcr |= UBRLCR_EVENPRT;
} }
if (port->fifosize > 1) if (port->fifosize > 1)
ubrlcr |= UBRLCR_FIFOEN; 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; port->read_status_mask = UARTDR_OVERR;
if (iflag & INPCK) if (termios->c_iflag & INPCK)
port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
/* /*
* Characters to ignore * Characters to ignore
*/ */
port->ignore_status_mask = 0; port->ignore_status_mask = 0;
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
if (iflag & IGNBRK) { if (termios->c_iflag & IGNBRK) {
/* /*
* If we're ignoring parity and break indicators, * If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support). * ignore overruns to (for real raw support).
*/ */
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_OVERR; port->ignore_status_mask |= UARTDR_OVERR;
} }
quot -= 1; quot -= 1;
/* first, disable everything */
spin_lock_irqsave(&port->lock, flags);
clps_writel(ubrlcr | quot, UBRLCR(port)); clps_writel(ubrlcr | quot, UBRLCR(port));
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
...@@ -411,7 +424,7 @@ static struct uart_ops clps711x_pops = { ...@@ -411,7 +424,7 @@ static struct uart_ops clps711x_pops = {
.break_ctl = clps711xuart_break_ctl, .break_ctl = clps711xuart_break_ctl,
.startup = clps711xuart_startup, .startup = clps711xuart_startup,
.shutdown = clps711xuart_shutdown, .shutdown = clps711xuart_shutdown,
.change_speed = clps711xuart_change_speed, .set_termios = clps711xuart_set_termios,
.type = clps711xuart_type, .type = clps711xuart_type,
.config_port = clps711xuart_config_port, .config_port = clps711xuart_config_port,
.release_port = clps711xuart_release_port, .release_port = clps711xuart_release_port,
......
...@@ -314,40 +314,68 @@ EXPORT_SYMBOL(uart_update_timeout); ...@@ -314,40 +314,68 @@ 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;
unsigned int flags = port->flags & UPF_SPD_MASK;
/* if (flags == UPF_SPD_HI)
* The spd_hi, spd_vhi, spd_shi, spd_warp kludge... altbaud = 57600;
* Die! Die! Die! if (flags == UPF_SPD_VHI)
*/ altbaud = 115200;
if (baud == 38400) { if (flags == UPF_SPD_SHI)
unsigned int flags = port->flags & UPF_SPD_MASK; altbaud = 230400;
if (flags == UPF_SPD_WARP)
if (flags == UPF_SPD_HI) altbaud = 460800;
baud = 57600;
if (flags == UPF_SPD_VHI)
baud = 115200;
if (flags == UPF_SPD_SHI)
baud = 230400;
if (flags == UPF_SPD_WARP)
baud = 460800;
}
/* for (try = 0; try < 2; try++) {
* Special case: B0 rate. baud = tty_termios_baud_rate(termios);
*/
if (baud == 0) /*
baud = 9600; * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
* Die! Die! Die!
*/
if (baud == 38400)
baud = altbaud;
/*
* Special case: B0 rate.
*/
if (baud == 0)
baud = 9600;
if (baud >= min && baud <= max)
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 baud; 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 */
baud = uart_get_baud_rate(port, termios);
quot = uart_calculate_quot(port, baud);
if (quot)
return quot;
/* /* Determine divisor based on baud rate */
* Oops, the quotient was zero. Try again with baud = uart_get_baud_rate(port, termios, old_termios, 0, max);
* 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, * Old custom speed handling.
* default to 9600 bps */
*/ if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
termios->c_cflag |= B9600; quot = port->custom_divisor;
} else
quot = port->uartclk / (16 * baud);
return quot; return quot;
} }
...@@ -451,10 +453,7 @@ uart_change_speed(struct uart_info *info, struct termios *old_termios) ...@@ -451,10 +453,7 @@ uart_change_speed(struct uart_info *info, struct termios *old_termios)
else else
info->flags |= UIF_CHECK_CD; info->flags |= UIF_CHECK_CD;
quot = uart_get_divisor(port, termios, old_termios); port->ops->set_termios(port, termios, old_termios);
uart_update_timeout(port, termios->c_cflag, quot);
port->ops->change_speed(port, termios->c_cflag, termios->c_iflag, quot);
} }
static inline void static inline void
...@@ -827,7 +826,7 @@ uart_set_info(struct uart_info *info, struct serial_struct *newinfo) ...@@ -827,7 +826,7 @@ uart_set_info(struct uart_info *info, struct serial_struct *newinfo)
port->irq = new_serial.irq; port->irq = new_serial.irq;
port->uartclk = new_serial.baud_base * 16; port->uartclk = new_serial.baud_base * 16;
port->flags = new_serial.flags & UPF_FLAGS; port->flags = new_serial.flags & UPF_CHANGE_MASK;
port->custom_divisor = new_serial.custom_divisor; port->custom_divisor = new_serial.custom_divisor;
state->close_delay = new_serial.close_delay * HZ / 100; state->close_delay = new_serial.close_delay * HZ / 100;
state->closing_wait = new_serial.closing_wait * HZ / 100; state->closing_wait = new_serial.closing_wait * HZ / 100;
...@@ -1267,7 +1266,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) ...@@ -1267,7 +1266,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
if (tty->ldisc.flush_buffer) if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty); tty->ldisc.flush_buffer(tty);
tty->closing = 0; tty->closing = 0;
info->event = 0;
info->tty = NULL; info->tty = NULL;
if (info->blocked_open) { if (info->blocked_open) {
if (info->state->close_delay) { if (info->state->close_delay) {
...@@ -1376,7 +1374,6 @@ static void uart_hangup(struct tty_struct *tty) ...@@ -1376,7 +1374,6 @@ static void uart_hangup(struct tty_struct *tty)
return; return;
} }
uart_shutdown(info); uart_shutdown(info);
info->event = 0;
state->count = 0; state->count = 0;
info->flags &= ~UIF_NORMAL_ACTIVE; info->flags &= ~UIF_NORMAL_ACTIVE;
info->tty = NULL; info->tty = NULL;
...@@ -1859,10 +1856,13 @@ int __init ...@@ -1859,10 +1856,13 @@ int __init
uart_set_options(struct uart_port *port, struct console *co, uart_set_options(struct uart_port *port, struct console *co,
int baud, int parity, int bits, int flow) int baud, int parity, int bits, int flow)
{ {
unsigned int cflag = CREAD | HUPCL | CLOCAL; struct termios termios;
unsigned int quot;
int i; int i;
memset(&termios, 0, sizeof(struct termios));
termios.c_cflag = CREAD | HUPCL | CLOCAL;
/* /*
* Construct a cflag setting. * Construct a cflag setting.
*/ */
...@@ -1870,28 +1870,27 @@ uart_set_options(struct uart_port *port, struct console *co, ...@@ -1870,28 +1870,27 @@ uart_set_options(struct uart_port *port, struct console *co,
if (baud_rates[i].rate <= baud) if (baud_rates[i].rate <= baud)
break; break;
cflag |= baud_rates[i].cflag; termios.c_cflag |= baud_rates[i].cflag;
if (bits == 7) if (bits == 7)
cflag |= CS7; termios.c_cflag |= CS7;
else else
cflag |= CS8; termios.c_cflag |= CS8;
switch (parity) { switch (parity) {
case 'o': case 'O': case 'o': case 'O':
cflag |= PARODD; termios.c_cflag |= PARODD;
/*fall through*/ /*fall through*/
case 'e': case 'E': case 'e': case 'E':
cflag |= PARENB; termios.c_cflag |= PARENB;
break; break;
} }
if (flow == 'r') if (flow == 'r')
cflag |= CRTSCTS; termios.c_cflag |= CRTSCTS;
co->cflag = cflag; port->ops->set_termios(port, &termios, NULL);
quot = (port->uartclk / (16 * baud)); co->cflag = termios.c_cflag;
port->ops->change_speed(port, cflag, 0, quot);
return 0; return 0;
} }
......
...@@ -268,17 +268,16 @@ static void mux_shutdown(struct uart_port *port) ...@@ -268,17 +268,16 @@ static void mux_shutdown(struct uart_port *port)
} }
/** /**
* mux_change_speed - Chane port parameters. * mux_set_termios - Chane port parameters.
* @port: Ptr to the uart_port. * @port: Ptr to the uart_port.
* @cflag: character flags. * @termios: new termios settings.
* @iflag: interrupt flags. * @old: old termios settings.
* @quot:
* *
* The Serial Mux does not support this function. * The Serial Mux does not support this function.
*/ */
static void static void
mux_change_speed(struct uart_port *port, unsigned int cflag, mux_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
} }
...@@ -388,7 +387,7 @@ static struct uart_ops mux_pops = { ...@@ -388,7 +387,7 @@ static struct uart_ops mux_pops = {
.break_ctl = mux_break_ctl, .break_ctl = mux_break_ctl,
.startup = mux_startup, .startup = mux_startup,
.shutdown = mux_shutdown, .shutdown = mux_shutdown,
.change_speed = mux_change_speed, .set_termios = mux_set_termios,
.type = mux_type, .type = mux_type,
.release_port = mux_release_port, .release_port = mux_release_port,
.request_port = mux_request_port, .request_port = mux_request_port,
......
...@@ -440,15 +440,13 @@ static void nb85e_uart_shutdown (struct uart_port *port) ...@@ -440,15 +440,13 @@ static void nb85e_uart_shutdown (struct uart_port *port)
} }
static void static void
nb85e_uart_change_speed (struct uart_port *port, unsigned cflags, nb85e_uart_set_termios (struct uart_port *port, struct termios *termios,
unsigned iflag, unsigned quot) struct termios *old)
{ {
/* The serial framework doesn't give us the baud rate directly, but /* FIXME: Which termios flags does this driver support? --rmk */
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);
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) static const char *nb85e_uart_type (struct uart_port *port)
...@@ -483,7 +481,7 @@ static struct uart_ops nb85e_uart_ops = { ...@@ -483,7 +481,7 @@ static struct uart_ops nb85e_uart_ops = {
.break_ctl = nb85e_uart_break_ctl, .break_ctl = nb85e_uart_break_ctl,
.startup = nb85e_uart_startup, .startup = nb85e_uart_startup,
.shutdown = nb85e_uart_shutdown, .shutdown = nb85e_uart_shutdown,
.change_speed = nb85e_uart_change_speed, .set_termios = nb85e_uart_set_termios,
.type = nb85e_uart_type, .type = nb85e_uart_type,
.release_port = nb85e_uart_nop, .release_port = nb85e_uart_nop,
.request_port = nb85e_uart_success, .request_port = nb85e_uart_success,
......
...@@ -436,36 +436,50 @@ static void sa1100_shutdown(struct uart_port *port) ...@@ -436,36 +436,50 @@ static void sa1100_shutdown(struct uart_port *port)
} }
static void static void
sa1100_change_speed(struct uart_port *port, unsigned int cflag, sa1100_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
struct sa1100_port *sport = (struct sa1100_port *)port; struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags; 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) { * We only support CS7 and CS8.
case CS7: */
utcr0 = 0; while ((termios->c_cflag & CSIZE) != CS7 &&
break; (termios->c_cflag & CSIZE) != CS8) {
default: termios->c_cflag &= ~CSIZE;
utcr0 = UTCR0_DSS; termios->c_cflag |= old_csize;
break; 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; utcr0 |= UTCR0_SBS;
if (cflag & PARENB) { if (termios->c_cflag & PARENB) {
utcr0 |= UTCR0_PE; utcr0 |= UTCR0_PE;
if (!(cflag & PARODD)) if (!(termios->c_cflag & PARODD))
utcr0 |= UTCR0_OES; 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 &= UTSR0_TO_SM(UTSR0_TFS);
sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR); sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
if (iflag & INPCK) if (termios->c_iflag & INPCK)
sport->port.read_status_mask |= sport->port.read_status_mask |=
UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
if (iflag & (BRKINT | PARMRK)) if (termios->c_iflag & (BRKINT | PARMRK))
sport->port.read_status_mask |= sport->port.read_status_mask |=
UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
...@@ -473,29 +487,36 @@ sa1100_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -473,29 +487,36 @@ sa1100_change_speed(struct uart_port *port, unsigned int cflag,
* Characters to ignore * Characters to ignore
*/ */
sport->port.ignore_status_mask = 0; sport->port.ignore_status_mask = 0;
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |= sport->port.ignore_status_mask |=
UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
if (iflag & IGNBRK) { if (termios->c_iflag & IGNBRK) {
sport->port.ignore_status_mask |= sport->port.ignore_status_mask |=
UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
/* /*
* If we're ignoring parity and break indicators, * If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support). * ignore overruns too (for real raw support).
*/ */
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |= sport->port.ignore_status_mask |=
UTSR1_TO_SM(UTSR1_ROR); UTSR1_TO_SM(UTSR1_ROR);
} }
del_timer_sync(&sport->timer); 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); old_utcr3 = UART_GET_UTCR3(sport);
UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)); 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 */ /* then, disable everything */
UART_PUT_UTCR3(sport, 0); UART_PUT_UTCR3(sport, 0);
...@@ -512,7 +533,7 @@ sa1100_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -512,7 +533,7 @@ sa1100_change_speed(struct uart_port *port, unsigned int cflag,
UART_PUT_UTCR3(sport, old_utcr3); 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); sa1100_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock_irqrestore(&sport->port.lock, flags);
...@@ -597,7 +618,7 @@ static struct uart_ops sa1100_pops = { ...@@ -597,7 +618,7 @@ static struct uart_ops sa1100_pops = {
.break_ctl = sa1100_break_ctl, .break_ctl = sa1100_break_ctl,
.startup = sa1100_startup, .startup = sa1100_startup,
.shutdown = sa1100_shutdown, .shutdown = sa1100_shutdown,
.change_speed = sa1100_change_speed, .set_termios = sa1100_set_termios,
.type = sa1100_type, .type = sa1100_type,
.release_port = sa1100_release_port, .release_port = sa1100_release_port,
.request_port = sa1100_request_port, .request_port = sa1100_request_port,
......
...@@ -763,20 +763,15 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla ...@@ -763,20 +763,15 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
} }
/* port->lock is not held. */ /* port->lock is not held. */
static void sunsab_change_speed(struct uart_port *port, unsigned int cflag, static void sunsab_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags; unsigned long flags;
int baud; int baud = uart_get_baud_rate(port, termios);
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud);
/* Undo what generic UART core did. */
baud = (SAB_BASE_BAUD / (quot * 16));
sunsab_convert_to_sab(up, cflag, iflag, baud);
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
} }
...@@ -819,7 +814,7 @@ static struct uart_ops sunsab_pops = { ...@@ -819,7 +814,7 @@ static struct uart_ops sunsab_pops = {
.break_ctl = sunsab_break_ctl, .break_ctl = sunsab_break_ctl,
.startup = sunsab_startup, .startup = sunsab_startup,
.shutdown = sunsab_shutdown, .shutdown = sunsab_shutdown,
.change_speed = sunsab_change_speed, .set_termios = sunsab_set_termios,
.type = sunsab_type, .type = sunsab_type,
.release_port = sunsab_release_port, .release_port = sunsab_release_port,
.request_port = sunsab_request_port, .request_port = sunsab_request_port,
......
...@@ -660,7 +660,7 @@ static int sunsu_startup(struct uart_port *port) ...@@ -660,7 +660,7 @@ static int sunsu_startup(struct uart_port *port)
/* /*
* Clear the FIFO buffers and disable them. * Clear the FIFO buffers and disable them.
* (they will be reeanbled in change_speed()) * (they will be reeanbled in set_termios())
*/ */
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) { if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
...@@ -714,7 +714,7 @@ static int sunsu_startup(struct uart_port *port) ...@@ -714,7 +714,7 @@ static int sunsu_startup(struct uart_port *port)
/* /*
* Finally, enable interrupts. Note: Modem status interrupts * Finally, enable interrupts. Note: Modem status interrupts
* are set via change_speed(), which will be occuring imminently * are set via set_termios(), which will be occuring imminently
* anyway, so we don't enable them here. * anyway, so we don't enable them here.
*/ */
up->ier = UART_IER_RLSI | UART_IER_RDI; up->ier = UART_IER_RLSI | UART_IER_RDI;
...@@ -844,6 +844,17 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -844,6 +844,17 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
if (up->port.type == PORT_16750) if (up->port.type == PORT_16750)
fcr |= UART_FCR7_64BYTE; 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; up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (iflag & INPCK) if (iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 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, ...@@ -879,11 +890,6 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
if (UART_ENABLE_MS(&up->port, cflag)) if (UART_ENABLE_MS(&up->port, cflag))
up->ier |= UART_IER_MSI; 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); serial_out(up, UART_IER, up->ier);
if (uart_config[up->port.type].flags & UART_STARTECH) { if (uart_config[up->port.type].flags & UART_STARTECH) {
...@@ -910,6 +916,20 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -910,6 +916,20 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
} }
static void
sunsu_set_termios(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) static void sunsu_release_port(struct uart_port *port)
{ {
} }
...@@ -960,7 +980,7 @@ static struct uart_ops sunsu_pops = { ...@@ -960,7 +980,7 @@ static struct uart_ops sunsu_pops = {
.break_ctl = sunsu_break_ctl, .break_ctl = sunsu_break_ctl,
.startup = sunsu_startup, .startup = sunsu_startup,
.shutdown = sunsu_shutdown, .shutdown = sunsu_shutdown,
.change_speed = sunsu_change_speed, .set_termios = sunsu_set_termios,
.type = sunsu_type, .type = sunsu_type,
.release_port = sunsu_release_port, .release_port = sunsu_release_port,
.request_port = sunsu_request_port, .request_port = sunsu_request_port,
......
...@@ -917,26 +917,27 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, ...@@ -917,26 +917,27 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
/* The port lock is not held. */ /* The port lock is not held. */
static void static void
sunzilog_change_speed(struct uart_port *port, unsigned int cflag, sunzilog_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
unsigned long flags; unsigned long flags;
int baud, brg; int baud, brg;
baud = uart_get_baud_rate(port, termios);
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
baud = (ZS_CLOCK / (quot * 16));
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); 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; up->flags |= SUNZILOG_FLAG_MODEM_STATUS;
else else
up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS; up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS;
up->cflag = cflag; up->cflag = termios->c_cflag;
sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
...@@ -982,7 +983,7 @@ static struct uart_ops sunzilog_pops = { ...@@ -982,7 +983,7 @@ static struct uart_ops sunzilog_pops = {
.break_ctl = sunzilog_break_ctl, .break_ctl = sunzilog_break_ctl,
.startup = sunzilog_startup, .startup = sunzilog_startup,
.shutdown = sunzilog_shutdown, .shutdown = sunzilog_shutdown,
.change_speed = sunzilog_change_speed, .set_termios = sunzilog_set_termios,
.type = sunzilog_type, .type = sunzilog_type,
.release_port = sunzilog_release_port, .release_port = sunzilog_release_port,
.request_port = sunzilog_request_port, .request_port = sunzilog_request_port,
......
...@@ -314,14 +314,24 @@ static void uart00_break_ctl(struct uart_port *port, int break_state) ...@@ -314,14 +314,24 @@ static void uart00_break_ctl(struct uart_port *port, int break_state)
} }
static void static void
uart00_change_speed(struct uart_port *port, unsigned int cflag, uart00_set_termios(struct uart_port *port, struct termios *termios,
unsigned int iflag, unsigned int quot) struct termios *old)
{ {
unsigned int uart_mc, old_ies; unsigned int uart_mc, old_ies, quot;
unsigned long flags; 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 */ /* byte size and parity */
switch (cflag & CSIZE) { switch (termios->c_cflag & CSIZE) {
case CS5: case CS5:
uart_mc = UART_MC_CLS_CHARLEN_5; uart_mc = UART_MC_CLS_CHARLEN_5;
break; break;
...@@ -335,41 +345,47 @@ uart00_change_speed(struct uart_port *port, unsigned int cflag, ...@@ -335,41 +345,47 @@ uart00_change_speed(struct uart_port *port, unsigned int cflag,
uart_mc = UART_MC_CLS_CHARLEN_8; uart_mc = UART_MC_CLS_CHARLEN_8;
break; break;
} }
if (cflag & CSTOPB) if (termios->c_cflag & CSTOPB)
uart_mc|= UART_MC_ST_TWO; uart_mc|= UART_MC_ST_TWO;
if (cflag & PARENB) { if (termios->c_cflag & PARENB) {
uart_mc |= UART_MC_PE_MSK; uart_mc |= UART_MC_PE_MSK;
if (!(cflag & PARODD)) if (!(termios->c_cflag & PARODD))
uart_mc |= UART_MC_EP_MSK; 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; 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; 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; port->read_status_mask |= UART_RDS_BI_MSK;
/* /*
* Characters to ignore * Characters to ignore
*/ */
port->ignore_status_mask = 0; 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; 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; port->ignore_status_mask |= UART_RDS_BI_MSK;
/* /*
* If we're ignoring parity and break indicators, * If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support). * ignore overruns to (for real raw support).
*/ */
if (iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_RDS_OE_MSK; port->ignore_status_mask |= UART_RDS_OE_MSK;
} }
/* first, disable everything */ /* first, disable everything */
spin_lock_irqsave(&port->lock, flags);
old_ies = UART_GET_IES(port); 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; old_ies |= UART_IES_ME_MSK;
/* Set baud rate */ /* Set baud rate */
...@@ -495,7 +511,7 @@ static struct uart_ops uart00_pops = { ...@@ -495,7 +511,7 @@ static struct uart_ops uart00_pops = {
.break_ctl = uart00_break_ctl, .break_ctl = uart00_break_ctl,
.startup = uart00_startup, .startup = uart00_startup,
.shutdown = uart00_shutdown, .shutdown = uart00_shutdown,
.change_speed = uart00_change_speed, .set_termios = uart00_set_termios,
.type = uart00_type, .type = uart00_type,
.release_port = uart00_release_port, .release_port = uart00_release_port,
.request_port = uart00_request_port, .request_port = uart00_request_port,
......
...@@ -86,8 +86,8 @@ struct uart_ops { ...@@ -86,8 +86,8 @@ struct uart_ops {
void (*break_ctl)(struct uart_port *, int ctl); void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *); int (*startup)(struct uart_port *);
void (*shutdown)(struct uart_port *); void (*shutdown)(struct uart_port *);
void (*change_speed)(struct uart_port *, unsigned int cflag, void (*set_termios)(struct uart_port *, struct termios *new,
unsigned int iflag, unsigned int quot); struct termios *old);
void (*pm)(struct uart_port *, unsigned int state, void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate); unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state); int (*set_wake)(struct uart_port *, unsigned int state);
...@@ -179,7 +179,7 @@ struct uart_port { ...@@ -179,7 +179,7 @@ struct uart_port {
#define UPF_RESOURCES (1 << 30) #define UPF_RESOURCES (1 << 30)
#define UPF_IOREMAP (1 << 31) #define UPF_IOREMAP (1 << 31)
#define UPF_FLAGS (0x7fff) #define UPF_CHANGE_MASK (0x7fff)
#define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY) #define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY)
unsigned int mctrl; /* current modem ctrl settings */ unsigned int mctrl; /* current modem ctrl settings */
...@@ -242,7 +242,6 @@ struct uart_info { ...@@ -242,7 +242,6 @@ struct uart_info {
unsigned char *tmpbuf; unsigned char *tmpbuf;
struct semaphore tmpbuf_sem; struct semaphore tmpbuf_sem;
unsigned long event;
int blocked_open; int blocked_open;
struct tasklet_struct tlet; struct tasklet_struct tlet;
...@@ -275,12 +274,31 @@ struct uart_driver { ...@@ -275,12 +274,31 @@ struct uart_driver {
}; };
void uart_write_wakeup(struct uart_port *port); void uart_write_wakeup(struct uart_port *port);
/*
* Baud rate helpers.
*/
void uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int quot);
unsigned int uart_get_baud_rate(struct uart_port *port, struct termios *termios
struct termios *old, unsigned int min,
unsigned int max);
unsigned int uart_get_divisor(struct uart_port *port, struct termios *termios,
struct termios *old_termios);
/*
* Console helpers.
*/
struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct uart_port *uart_get_console(struct uart_port *ports, int nr,
struct console *c); struct console *c);
void uart_parse_options(char *options, int *baud, int *parity, int *bits, void uart_parse_options(char *options, int *baud, int *parity, int *bits,
int *flow); int *flow);
int uart_set_options(struct uart_port *port, struct console *co, int baud, int uart_set_options(struct uart_port *port, struct console *co, int baud,
int parity, int bits, int flow); int parity, int bits, int flow);
/*
* Port/driver registration/removal
*/
int uart_register_driver(struct uart_driver *uart); int uart_register_driver(struct uart_driver *uart);
void uart_unregister_driver(struct uart_driver *uart); void uart_unregister_driver(struct uart_driver *uart);
void uart_unregister_port(struct uart_driver *reg, int line); void uart_unregister_port(struct uart_driver *reg, int line);
......
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