Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9e6077bd84a7bffa73b59d9704682aeab5781fa0
Commit:     9e6077bd84a7bffa73b59d9704682aeab5781fa0
Parent:     cc1ed7542c8c26af0f501da8006b9fce03e9aaca
Author:     Haavard Skinnemoen <[EMAIL PROTECTED]>
AuthorDate: Sun Jul 15 23:40:36 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Mon Jul 16 09:05:45 2007 -0700

    atmel_serial: fix break handling
    
    The RXBRK field in the AT91/AT32 USART status register has the
    following definition according to e.g. the AT32AP7000 data sheet:
    
        RXBRK: Break Received/End of Break
        0: No Break received or End of Break detected since the last RSTSTA.
        1: Break Received or End of Break detected since the last RSTSTA.
    
    Thus, for each break, the USART sets the RXBRK bit twice. This patch
    modifies the driver to report the break event to the serial core only
    once by keeping track of whether a break condition is currently
    active. The break_active flag is reset as soon as a character is
    received, so even if we miss the start-of-break interrupt this should
    do the right thing.
    
    Signed-off-by: Haavard Skinnemoen <[EMAIL PROTECTED]>
    Cc: Andrew Victor <[EMAIL PROTECTED]>
    Cc: Russell King <[EMAIL PROTECTED]>
    Cc: Ivan Kuten <[EMAIL PROTECTED]>
    Cc: Nicolas Ferre <[EMAIL PROTECTED]>
    Cc: Patrice Vilchez <[EMAIL PROTECTED]>
    Cc: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 drivers/serial/atmel_serial.c |   32 ++++++++++++++++++++++++++++++--
 1 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 3320bcd..4d6b3c5 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -114,6 +114,7 @@ struct atmel_uart_port {
        struct uart_port        uart;           /* uart */
        struct clk              *clk;           /* uart clock */
        unsigned short          suspended;      /* is port suspended? */
+       int                     break_active;   /* break being received */
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -252,6 +253,7 @@ static void atmel_break_ctl(struct uart_port *port, int 
break_state)
  */
 static void atmel_rx_chars(struct uart_port *port)
 {
+       struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
        struct tty_struct *tty = port->info->tty;
        unsigned int status, ch, flg;
 
@@ -267,13 +269,29 @@ static void atmel_rx_chars(struct uart_port *port)
                 * note that the error handling code is
                 * out of the main execution path
                 */
-               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | 
ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK)
+                            || atmel_port->break_active)) {
                        UART_PUT_CR(port, ATMEL_US_RSTSTA);     /* clear error 
*/
-                       if (status & ATMEL_US_RXBRK) {
+                       if (status & ATMEL_US_RXBRK
+                           && !atmel_port->break_active) {
                                status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);    
/* ignore side-effect */
                                port->icount.brk++;
+                               atmel_port->break_active = 1;
+                               UART_PUT_IER(port, ATMEL_US_RXBRK);
                                if (uart_handle_break(port))
                                        goto ignore_char;
+                       } else {
+                               /*
+                                * This is either the end-of-break
+                                * condition or we've received at
+                                * least one character without RXBRK
+                                * being set. In both cases, the next
+                                * RXBRK will indicate start-of-break.
+                                */
+                               UART_PUT_IDR(port, ATMEL_US_RXBRK);
+                               status &= ~ATMEL_US_RXBRK;
+                               atmel_port->break_active = 0;
                        }
                        if (status & ATMEL_US_PARE)
                                port->icount.parity++;
@@ -352,6 +370,16 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
                /* Interrupt receive */
                if (pending & ATMEL_US_RXRDY)
                        atmel_rx_chars(port);
+               else if (pending & ATMEL_US_RXBRK) {
+                       /*
+                        * End of break detected. If it came along
+                        * with a character, atmel_rx_chars will
+                        * handle it.
+                        */
+                       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+                       UART_PUT_IDR(port, ATMEL_US_RXBRK);
+                       atmel_port->break_active = 0;
+               }
 
                // TODO: All reads to CSR will clear these interrupts!
                if (pending & ATMEL_US_RIIC) port->icount.rng++;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to