[PATCH] TTY layer buffering revamp
[pandora-kernel.git] / drivers / serial / 8250.c
index 3742753..54e5cc0 100644 (file)
@@ -54,6 +54,8 @@
  */
 static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
+static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
+
 /*
  * Debugging.
  */
@@ -102,7 +104,7 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 #define SERIAL_PORT_DFNS
 #endif
 
-static struct old_serial_port old_serial_port[] = {
+static const struct old_serial_port old_serial_port[] = {
        SERIAL_PORT_DFNS /* defined in asm/serial.h */
 };
 
@@ -296,7 +298,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
 
 #endif
 
-static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
+static unsigned int serial_in(struct uart_8250_port *up, int offset)
 {
        offset = map_8250_in_reg(up, offset) << up->port.regshift;
 
@@ -321,7 +323,7 @@ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
        }
 }
 
-static _INLINE_ void
+static void
 serial_out(struct uart_8250_port *up, int offset, int value)
 {
        offset = map_8250_out_reg(up, offset) << up->port.regshift;
@@ -999,7 +1001,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        serial_outp(up, UART_MCR, save_mcr);
        serial8250_clear_fifos(up);
        (void)serial_in(up, UART_RX);
-       serial_outp(up, UART_IER, 0);
+       if (up->capabilities & UART_CAP_UUE)
+               serial_outp(up, UART_IER, UART_IER_UUE);
+       else
+               serial_outp(up, UART_IER, 0);
 
  out:  
        spin_unlock_irqrestore(&up->port.lock, flags);
@@ -1128,7 +1133,7 @@ static void serial8250_enable_ms(struct uart_port *port)
        serial_out(up, UART_IER, up->ier);
 }
 
-static _INLINE_ void
+static void
 receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
 {
        struct tty_struct *tty = up->port.info->tty;
@@ -1137,19 +1142,6 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
        char flag;
 
        do {
-               /* The following is not allowed by the tty layer and
-                  unsafe. It should be fixed ASAP */
-               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-                       if (tty->low_latency) {
-                               spin_unlock(&up->port.lock);
-                               tty_flip_buffer_push(tty);
-                               spin_lock(&up->port.lock);
-                       }
-                       /*
-                        * If this failed then we will throw away the
-                        * bytes but must do so to clear interrupts
-                        */
-               }
                ch = serial_inp(up, UART_RX);
                flag = TTY_NORMAL;
                up->port.icount.rx++;
@@ -1214,7 +1206,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
        *status = lsr;
 }
 
-static _INLINE_ void transmit_chars(struct uart_8250_port *up)
+static void transmit_chars(struct uart_8250_port *up)
 {
        struct circ_buf *xmit = &up->port.info->xmit;
        int count;
@@ -1252,25 +1244,24 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
                __stop_tx(up);
 }
 
-static _INLINE_ void check_modem_status(struct uart_8250_port *up)
+static unsigned int check_modem_status(struct uart_8250_port *up)
 {
-       int status;
-
-       status = serial_in(up, UART_MSR);
+       unsigned int status = serial_in(up, UART_MSR);
 
-       if ((status & UART_MSR_ANY_DELTA) == 0)
-               return;
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {
+               if (status & UART_MSR_TERI)
+                       up->port.icount.rng++;
+               if (status & UART_MSR_DDSR)
+                       up->port.icount.dsr++;
+               if (status & UART_MSR_DDCD)
+                       uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+               if (status & UART_MSR_DCTS)
+                       uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
 
-       if (status & UART_MSR_TERI)
-               up->port.icount.rng++;
-       if (status & UART_MSR_DDSR)
-               up->port.icount.dsr++;
-       if (status & UART_MSR_DDCD)
-               uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
-       if (status & UART_MSR_DCTS)
-               uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+               wake_up_interruptible(&up->port.info->delta_msr_wait);
+       }
 
-       wake_up_interruptible(&up->port.info->delta_msr_wait);
+       return status;
 }
 
 /*
@@ -1279,7 +1270,11 @@ static _INLINE_ void check_modem_status(struct uart_8250_port *up)
 static inline void
 serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
 {
-       unsigned int status = serial_inp(up, UART_LSR);
+       unsigned int status;
+
+       spin_lock(&up->port.lock);
+
+       status = serial_inp(up, UART_LSR);
 
        DEBUG_INTR("status = %x...", status);
 
@@ -1288,6 +1283,8 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
        check_modem_status(up);
        if (status & UART_LSR_THRE)
                transmit_chars(up);
+
+       spin_unlock(&up->port.lock);
 }
 
 /*
@@ -1323,9 +1320,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r
 
                iir = serial_in(up, UART_IIR);
                if (!(iir & UART_IIR_NO_INT)) {
-                       spin_lock(&up->port.lock);
                        serial8250_handle_port(up, regs);
-                       spin_unlock(&up->port.lock);
 
                        handled = 1;
 
@@ -1424,11 +1419,8 @@ static void serial8250_timeout(unsigned long data)
        unsigned int iir;
 
        iir = serial_in(up, UART_IIR);
-       if (!(iir & UART_IIR_NO_INT)) {
-               spin_lock(&up->port.lock);
+       if (!(iir & UART_IIR_NO_INT))
                serial8250_handle_port(up, NULL);
-               spin_unlock(&up->port.lock);
-       }
 
        timeout = up->port.timeout;
        timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@@ -1451,10 +1443,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
-       unsigned char status;
+       unsigned int status;
        unsigned int ret;
 
-       status = serial_in(up, UART_MSR);
+       status = check_modem_status(up);
 
        ret = 0;
        if (status & UART_MSR_DCD)
@@ -2115,7 +2107,7 @@ static void __init serial8250_isa_init_ports(void)
                return;
        first = 0;
 
-       for (i = 0; i < UART_NR; i++) {
+       for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
                up->port.line = i;
@@ -2134,7 +2126,7 @@ static void __init serial8250_isa_init_ports(void)
        }
 
        for (i = 0, up = serial8250_ports;
-            i < ARRAY_SIZE(old_serial_port) && i < UART_NR;
+            i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
             i++, up++) {
                up->port.iobase   = old_serial_port[i].port;
                up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
@@ -2156,7 +2148,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 
        serial8250_isa_init_ports();
 
-       for (i = 0; i < UART_NR; i++) {
+       for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
                up->port.dev = dev;
@@ -2259,7 +2251,7 @@ static int serial8250_console_setup(struct console *co, char *options)
         * if so, search for the first available port that does have
         * console support.
         */
-       if (co->index >= UART_NR)
+       if (co->index >= nr_uarts)
                co->index = 0;
        port = &serial8250_ports[co->index].port;
        if (!port->iobase && !port->membase)
@@ -2295,11 +2287,9 @@ static int __init find_port(struct uart_port *p)
        int line;
        struct uart_port *port;
 
-       for (line = 0; line < UART_NR; line++) {
+       for (line = 0; line < nr_uarts; line++) {
                port = &serial8250_ports[line].port;
-               if (p->iotype == port->iotype &&
-                   p->iobase == port->iobase &&
-                   p->membase == port->membase)
+               if (uart_match_port(p, port))
                        return line;
        }
        return -ENODEV;
@@ -2419,7 +2409,7 @@ static int __devexit serial8250_remove(struct platform_device *dev)
 {
        int i;
 
-       for (i = 0; i < UART_NR; i++) {
+       for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
                if (up->port.dev == &dev->dev)
@@ -2486,7 +2476,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
        /*
         * First, find a port entry which matches.
         */
-       for (i = 0; i < UART_NR; i++)
+       for (i = 0; i < nr_uarts; i++)
                if (uart_match_port(&serial8250_ports[i].port, port))
                        return &serial8250_ports[i];
 
@@ -2495,7 +2485,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
         * free entry.  We look for one which hasn't been previously
         * used (indicated by zero iobase).
         */
-       for (i = 0; i < UART_NR; i++)
+       for (i = 0; i < nr_uarts; i++)
                if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
                    serial8250_ports[i].port.iobase == 0)
                        return &serial8250_ports[i];
@@ -2504,7 +2494,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
         * That also failed.  Last resort is to find any entry which
         * doesn't have a real port associated with it.
         */
-       for (i = 0; i < UART_NR; i++)
+       for (i = 0; i < nr_uarts; i++)
                if (serial8250_ports[i].port.type == PORT_UNKNOWN)
                        return &serial8250_ports[i];
 
@@ -2589,8 +2579,11 @@ static int __init serial8250_init(void)
 {
        int ret, i;
 
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
+
        printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
-               "%d ports, IRQ sharing %sabled\n", (int) UART_NR,
+               "%d ports, IRQ sharing %sabled\n", nr_uarts,
                share_irqs ? "en" : "dis");
 
        for (i = 0; i < NR_IRQS; i++)
@@ -2650,6 +2643,9 @@ module_param(share_irqs, uint, 0644);
 MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
        " (unsafe)");
 
+module_param(nr_uarts, uint, 0644);
+MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
+
 #ifdef CONFIG_SERIAL_8250_RSA
 module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
 MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");