]> err.no Git - linux-2.6/blobdiff - drivers/serial/8250.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6] / drivers / serial / 8250.c
index 77f7a7f0646e00ce1bbfb0b2fb439c283df06887..1400ea6a249192e9a322a5c006595b6ee250e783 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/serial.h>
 
 #include "8250.h"
 
@@ -92,8 +93,6 @@ static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
  */
 #define CONFIG_HUB6 1
 
-#include <asm/serial.h>
-
 /*
  * SERIAL_PORT_DFNS tells us about built-in ports that have no
  * standard enumeration mechanism.   Platforms that can find all
@@ -1548,6 +1547,8 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
                i->head = &up->list;
                spin_unlock_irq(&i->lock);
 
+               irq_flags |= SERIAL_EXTRA_IRQ_FLAGS;
+
                ret = request_irq(up->port.irq, serial8250_interrupt,
                                  irq_flags, "serial", i);
                if (ret < 0)
@@ -1740,6 +1741,60 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
        }
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial8250_get_poll_char(struct uart_port *port)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)port;
+       unsigned char lsr = serial_inp(up, UART_LSR);
+
+       while (!(lsr & UART_LSR_DR))
+               lsr = serial_inp(up, UART_LSR);
+
+       return serial_inp(up, UART_RX);
+}
+
+
+static void serial8250_put_poll_char(struct uart_port *port,
+                        unsigned char c)
+{
+       unsigned int ier;
+       struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = serial_in(up, UART_IER);
+       if (up->capabilities & UART_CAP_UUE)
+               serial_out(up, UART_IER, UART_IER_UUE);
+       else
+               serial_out(up, UART_IER, 0);
+
+       wait_for_xmitr(up, BOTH_EMPTY);
+       /*
+        *      Send the character out.
+        *      If a LF, also do CR...
+        */
+       serial_out(up, UART_TX, c);
+       if (c == 10) {
+               wait_for_xmitr(up, BOTH_EMPTY);
+               serial_out(up, UART_TX, 13);
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up, BOTH_EMPTY);
+       serial_out(up, UART_IER, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
 static int serial8250_startup(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -1814,6 +1869,7 @@ static int serial8250_startup(struct uart_port *port)
        }
 
        if (is_real_interrupt(up->port.irq)) {
+               unsigned char iir1;
                /*
                 * Test for UARTs that do not reassert THRE when the
                 * transmitter is idle and the interrupt has already
@@ -1827,7 +1883,7 @@ static int serial8250_startup(struct uart_port *port)
                wait_for_xmitr(up, UART_LSR_THRE);
                serial_out_sync(up, UART_IER, UART_IER_THRI);
                udelay(1); /* allow THRE to set */
-               serial_in(up, UART_IIR);
+               iir1 = serial_in(up, UART_IIR);
                serial_out(up, UART_IER, 0);
                serial_out_sync(up, UART_IER, UART_IER_THRI);
                udelay(1); /* allow a working UART time to re-assert THRE */
@@ -1840,7 +1896,7 @@ static int serial8250_startup(struct uart_port *port)
                 * If the interrupt is not reasserted, setup a timer to
                 * kick the UART on a regular basis.
                 */
-               if (iir & UART_IIR_NO_INT) {
+               if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
                        pr_debug("ttyS%d - using backup timer\n", port->line);
                        up->timer.function = serial8250_backup_timeout;
                        up->timer.data = (unsigned long)up;
@@ -2174,7 +2230,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
        }
        serial8250_set_mctrl(&up->port, up->port.mctrl);
        spin_unlock_irqrestore(&up->port.lock, flags);
-       tty_termios_encode_baud_rate(termios, baud, baud);
+       /* Don't rewrite B0 */
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
 }
 
 static void
@@ -2214,7 +2272,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
                }
 
                if (up->port.flags & UPF_IOREMAP) {
-                       up->port.membase = ioremap(up->port.mapbase, size);
+                       up->port.membase = ioremap_nocache(up->port.mapbase,
+                                                                       size);
                        if (!up->port.membase) {
                                release_mem_region(up->port.mapbase, size);
                                ret = -ENOMEM;
@@ -2386,6 +2445,10 @@ static struct uart_ops serial8250_pops = {
        .request_port   = serial8250_request_port,
        .config_port    = serial8250_config_port,
        .verify_port    = serial8250_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = serial8250_get_poll_char,
+       .poll_put_char = serial8250_put_poll_char,
+#endif
 };
 
 static struct uart_8250_port serial8250_ports[UART_NR];