Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 64227
b: refs/heads/master
c: ad4c2aa
h: refs/heads/master
i:
  64225: 50a58f0
  64223: 1699a88
v: v3
  • Loading branch information
Corey Minyard authored and Linus Torvalds committed Aug 23, 2007
1 parent f6add3f commit 81ed47d
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 30 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 999999616e45c603da45ee2667741fb7348629a5
refs/heads/master: ad4c2aa6354fad5316565b1cff57f80db0e04db8
85 changes: 56 additions & 29 deletions trunk/drivers/serial/8250.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,16 @@ struct uart_8250_port {
unsigned char mcr;
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
unsigned char lsr_break_flag;

/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;

/*
* We provide a per-port pm hook.
Expand Down Expand Up @@ -1238,6 +1247,7 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr, iir;
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
iir = serial_in(up, UART_IIR) & 0x0f;
if ((up->port.type == PORT_RM9000) ?
(lsr & UART_LSR_THRE &&
Expand Down Expand Up @@ -1290,18 +1300,10 @@ receive_chars(struct uart_8250_port *up, unsigned int *status)
flag = TTY_NORMAL;
up->port.icount.rx++;

#ifdef CONFIG_SERIAL_8250_CONSOLE
/*
* Recover the break flag from console xmit
*/
if (up->port.line == up->port.cons->index) {
lsr |= up->lsr_break_flag;
up->lsr_break_flag = 0;
}
#endif
lsr |= up->lsr_saved_flags;
up->lsr_saved_flags = 0;

if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE))) {
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
/*
* For statistics only
*/
Expand Down Expand Up @@ -1392,6 +1394,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
{
unsigned int status = serial_in(up, UART_MSR);

status |= up->msr_saved_flags;
up->msr_saved_flags = 0;
if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
up->port.info != NULL) {
if (status & UART_MSR_TERI)
Expand Down Expand Up @@ -1591,7 +1595,8 @@ static void serial8250_timeout(unsigned long data)
static void serial8250_backup_timeout(unsigned long data)
{
struct uart_8250_port *up = (struct uart_8250_port *)data;
unsigned int iir, ier = 0;
unsigned int iir, ier = 0, lsr;
unsigned long flags;

/*
* Must disable interrupts or else we risk racing with the interrupt
Expand All @@ -1610,9 +1615,13 @@ static void serial8250_backup_timeout(unsigned long data)
* the "Diva" UART used on the management processor on many HP
* ia64 and parisc boxes.
*/
spin_lock_irqsave(&up->port.lock, flags);
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
spin_unlock_irqrestore(&up->port.lock, flags);
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
(!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
(serial_in(up, UART_LSR) & UART_LSR_THRE)) {
(lsr & UART_LSR_THRE)) {
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
iir |= UART_IIR_THRI;
}
Expand All @@ -1631,13 +1640,14 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
unsigned int ret;
unsigned int lsr;

spin_lock_irqsave(&up->port.lock, flags);
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
spin_unlock_irqrestore(&up->port.lock, flags);

return ret;
return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
}

static unsigned int serial8250_get_mctrl(struct uart_port *port)
Expand Down Expand Up @@ -1708,8 +1718,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
do {
status = serial_in(up, UART_LSR);

if (status & UART_LSR_BI)
up->lsr_break_flag = UART_LSR_BI;
up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;

if (--tmout == 0)
break;
Expand All @@ -1718,8 +1727,12 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)

/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
tmout = 1000000;
while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
unsigned int tmout;
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
if (msr & UART_MSR_CTS)
break;
udelay(1);
touch_nmi_watchdog();
}
Expand Down Expand Up @@ -1888,6 +1901,18 @@ static int serial8250_startup(struct uart_port *port)

spin_unlock_irqrestore(&up->port.lock, flags);

/*
* Clear the interrupt registers again for luck, and clear the
* saved flags to avoid getting false values from polling
* routines or the previous session.
*/
serial_inp(up, UART_LSR);
serial_inp(up, UART_RX);
serial_inp(up, UART_IIR);
serial_inp(up, UART_MSR);
up->lsr_saved_flags = 0;
up->msr_saved_flags = 0;

/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
Expand All @@ -1906,14 +1931,6 @@ static int serial8250_startup(struct uart_port *port)
(void) inb_p(icp);
}

/*
* And clear the interrupt registers again for luck.
*/
(void) serial_inp(up, UART_LSR);
(void) serial_inp(up, UART_RX);
(void) serial_inp(up, UART_IIR);
(void) serial_inp(up, UART_MSR);

return 0;
}

Expand Down Expand Up @@ -2484,6 +2501,16 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
wait_for_xmitr(up, BOTH_EMPTY);
serial_out(up, UART_IER, ier);

/*
* The receive handling will happen properly because the
* receive ready bit will still be set; it is not cleared
* on read. However, modem control will not, we must
* call it if we have saved something in the saved flags
* while processing with interrupts off.
*/
if (up->msr_saved_flags)
check_modem_status(up);

if (locked)
spin_unlock(&up->port.lock);
local_irq_restore(flags);
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/serial_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
#define UART_LSR_PE 0x04 /* Parity error indicator */
#define UART_LSR_OE 0x02 /* Overrun error indicator */
#define UART_LSR_DR 0x01 /* Receiver data ready */
#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */

#define UART_MSR 6 /* In: Modem Status Register */
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
Expand Down

0 comments on commit 81ed47d

Please sign in to comment.