Merge /spare/repo/netdev-2.6 branch 'ieee80211'
[safe/jmp/linux-2.6] / drivers / serial / 8250.c
index 201c3b9..34e75bc 100644 (file)
@@ -51,7 +51,7 @@
  *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option
  *                is unsafe when used on edge-triggered interrupts.
  */
-unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
+static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
 /*
  * Debugging.
@@ -77,23 +77,9 @@ unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
  */
 #define is_real_interrupt(irq) ((irq) != 0)
 
-/*
- * This converts from our new CONFIG_ symbols to the symbols
- * that asm/serial.h expects.  You _NEED_ to comment out the
- * linux/config.h include contained inside asm/serial.h for
- * this to work.
- */
-#undef CONFIG_SERIAL_MANY_PORTS
-#undef CONFIG_SERIAL_DETECT_IRQ
-#undef CONFIG_SERIAL_MULTIPORT
-#undef CONFIG_HUB6
-
 #ifdef CONFIG_SERIAL_8250_DETECT_IRQ
 #define CONFIG_SERIAL_DETECT_IRQ 1
 #endif
-#ifdef CONFIG_SERIAL_8250_MULTIPORT
-#define CONFIG_SERIAL_MULTIPORT 1
-#endif
 #ifdef CONFIG_SERIAL_8250_MANY_PORTS
 #define CONFIG_SERIAL_MANY_PORTS 1
 #endif
@@ -132,9 +118,9 @@ struct uart_8250_port {
        struct uart_port        port;
        struct timer_list       timer;          /* "no irq" timer */
        struct list_head        list;           /* ports on this IRQ */
-       unsigned int            capabilities;   /* port capabilities */
+       unsigned short          capabilities;   /* port capabilities */
+       unsigned short          bugs;           /* port bugs */
        unsigned int            tx_loadsz;      /* transmit fifo load size */
-       unsigned short          rev;
        unsigned char           acr;
        unsigned char           ier;
        unsigned char           lcr;
@@ -560,7 +546,14 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
        if (id1 == 0x16 && id2 == 0xC9 &&
            (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
                up->port.type = PORT_16C950;
-               up->rev = rev | (id3 << 8);
+
+               /*
+                * Enable work around for the Oxford Semiconductor 952 rev B
+                * chip which causes it to seriously miscalculate baud rates
+                * when DLL is 0.
+                */
+               if (id3 == 0x52 && rev == 0x01)
+                       up->bugs |= UART_BUG_QUOT;
                return;
        }
        
@@ -577,8 +570,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
 
        id2 = id1 >> 8;
        if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
-               if (id2 == 0x10)
-                       up->rev = id1 & 255;
                up->port.type = PORT_16850;
                return;
        }
@@ -682,8 +673,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
         * from EXCR1. Switch back to bank 0, change it in MCR. Then
         * switch back to bank 2, read it from EXCR1 again and check
         * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
-        * On PowerPC we don't want to change baud_base, as we have
-        * a number of different divisors.  -- Tom Rini
         */
        serial_outp(up, UART_LCR, 0);
        status1 = serial_in(up, UART_MCR);
@@ -699,16 +688,25 @@ static void autoconfig_16550a(struct uart_8250_port *up)
                serial_outp(up, UART_MCR, status1);
 
                if ((status2 ^ status1) & UART_MCR_LOOP) {
-#ifndef CONFIG_PPC
+                       unsigned short quot;
+
                        serial_outp(up, UART_LCR, 0xE0);
+
+                       quot = serial_inp(up, UART_DLM) << 8;
+                       quot += serial_inp(up, UART_DLL);
+                       quot <<= 3;
+
                        status1 = serial_in(up, 0x04); /* EXCR1 */
                        status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
                        status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
                        serial_outp(up, 0x04, status1);
+                       
+                       serial_outp(up, UART_DLL, quot & 0xff);
+                       serial_outp(up, UART_DLM, quot >> 8);
+
                        serial_outp(up, UART_LCR, 0);
-                       up->port.uartclk = 921600*16;
-#endif
 
+                       up->port.uartclk = 921600*16;
                        up->port.type = PORT_NS16550A;
                        up->capabilities |= UART_NATSEMI;
                        return;
@@ -802,6 +800,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
 //     save_flags(flags); cli();
 
        up->capabilities = 0;
+       up->bugs = 0;
 
        if (!(up->port.flags & UPF_BUGGY_UART)) {
                /*
@@ -1014,6 +1013,8 @@ static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
        }
 }
 
+static void transmit_chars(struct uart_8250_port *up);
+
 static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -1021,6 +1022,14 @@ static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
        if (!(up->ier & UART_IER_THRI)) {
                up->ier |= UART_IER_THRI;
                serial_out(up, UART_IER, up->ier);
+
+               if (up->bugs & UART_BUG_TXEN) {
+                       unsigned char lsr, iir;
+                       lsr = serial_in(up, UART_LSR);
+                       iir = serial_in(up, UART_IIR);
+                       if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)
+                               transmit_chars(up);
+               }
        }
        /*
         * We only do this from uart_start
@@ -1065,8 +1074,10 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
                                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 */
+                       /*
+                        * 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;
@@ -1106,7 +1117,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
                                up->port.icount.overrun++;
 
                        /*
-                        * Mask off conditions which should be ingored.
+                        * Mask off conditions which should be ignored.
                         */
                        lsr &= up->port.read_status_mask;
 
@@ -1120,18 +1131,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
                }
                if (uart_handle_sysrq_char(&up->port, ch, regs))
                        goto ignore_char;
-               if ((lsr & up->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if ((lsr & UART_LSR_OE) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+
+               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+
        ignore_char:
                lsr = serial_inp(up, UART_LSR);
        } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
@@ -1433,6 +1435,7 @@ static int serial8250_startup(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
        unsigned long flags;
+       unsigned char lsr, iir;
        int retval;
 
        up->capabilities = uart_config[up->port.type].flags;
@@ -1536,6 +1539,26 @@ static int serial8250_startup(struct uart_port *port)
                        up->port.mctrl |= TIOCM_OUT2;
 
        serial8250_set_mctrl(&up->port, up->port.mctrl);
+
+       /*
+        * Do a quick test to see if we receive an
+        * interrupt when we enable the TX irq.
+        */
+       serial_outp(up, UART_IER, UART_IER_THRI);
+       lsr = serial_in(up, UART_LSR);
+       iir = serial_in(up, UART_IIR);
+       serial_outp(up, UART_IER, 0);
+
+       if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+               if (!(up->bugs & UART_BUG_TXEN)) {
+                       up->bugs |= UART_BUG_TXEN;
+                       pr_debug("ttyS%d - enabling bad tx status workarounds\n",
+                                port->line);
+               }
+       } else {
+               up->bugs &= ~UART_BUG_TXEN;
+       }
+
        spin_unlock_irqrestore(&up->port.lock, flags);
 
        /*
@@ -1645,22 +1668,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
-               cval = 0x00;
+               cval = UART_LCR_WLEN5;
                break;
        case CS6:
-               cval = 0x01;
+               cval = UART_LCR_WLEN6;
                break;
        case CS7:
-               cval = 0x02;
+               cval = UART_LCR_WLEN7;
                break;
        default:
        case CS8:
-               cval = 0x03;
+               cval = UART_LCR_WLEN8;
                break;
        }
 
        if (termios->c_cflag & CSTOPB)
-               cval |= 0x04;
+               cval |= UART_LCR_STOP;
        if (termios->c_cflag & PARENB)
                cval |= UART_LCR_PARITY;
        if (!(termios->c_cflag & PARODD))
@@ -1677,12 +1700,9 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
        quot = serial8250_get_divisor(port, baud);
 
        /*
-        * Work around a bug in the Oxford Semiconductor 952 rev B
-        * chip which causes it to seriously miscalculate baud rates
-        * when DLL is 0.
+        * Oxford Semi 952 rev B workaround
         */
-       if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
-           up->rev == 0x5201)
+       if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
                quot ++;
 
        if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
@@ -2289,10 +2309,11 @@ static int __devinit serial8250_probe(struct device *dev)
 {
        struct plat_serial8250_port *p = dev->platform_data;
        struct uart_port port;
+       int ret, i;
 
        memset(&port, 0, sizeof(struct uart_port));
 
-       for (; p && p->flags != 0; p++) {
+       for (i = 0; p && p->flags != 0; p++, i++) {
                port.iobase     = p->iobase;
                port.membase    = p->membase;
                port.irq        = p->irq;
@@ -2301,10 +2322,16 @@ static int __devinit serial8250_probe(struct device *dev)
                port.iotype     = p->iotype;
                port.flags      = p->flags;
                port.mapbase    = p->mapbase;
+               port.hub6       = p->hub6;
                port.dev        = dev;
                if (share_irqs)
                        port.flags |= UPF_SHARE_IRQ;
-               serial8250_register_port(&port);
+               ret = serial8250_register_port(&port);
+               if (ret < 0) {
+                       dev_err(dev, "unable to register port at index %d "
+                               "(IO%lx MEM%lx IRQ%d): %d\n", i,
+                               p->iobase, p->mapbase, p->irq, ret);
+               }
        }
        return 0;
 }
@@ -2570,6 +2597,9 @@ MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
  *     If this fails an error is returned.
  *
  *     On success the port is ready to use and the line number is returned.
+ *
+ *     Note: this function is deprecated - use serial8250_register_port
+ *     instead.
  */
 int register_serial(struct serial_struct *req)
 {
@@ -2624,6 +2654,9 @@ EXPORT_SYMBOL(register_serial);
  *
  *     Remove one serial port.  This may not be called from interrupt
  *     context.  We hand the port back to our local PM control.
+ *
+ *     Note: this function is deprecated - use serial8250_unregister_port
+ *     instead.
  */
 void unregister_serial(int line)
 {