fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / serial / 8250.c
index 7aca22c..545f508 100644 (file)
@@ -7,6 +7,9 @@
  *
  *  Copyright (C) 2001 Russell King.
  *
+ *  2005/09/16: Enabled higher baud rates for 16C95x.
+ *             (Mathias Adam <a2@adamis.de>)
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -19,7 +22,6 @@
  *  mapbase is the physical address of the IO port.
  *  membase is an 'ioremapped' cookie.
  */
-#include <linux/config.h>
 
 #if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -49,7 +51,7 @@
 
 /*
  * Configuration:
- *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option
+ *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
  *                is unsafe when used on edge-triggered interrupts.
  */
 static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
@@ -300,6 +302,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
 
 static unsigned int serial_in(struct uart_8250_port *up, int offset)
 {
+       unsigned int tmp;
        offset = map_8250_in_reg(up, offset) << up->port.regshift;
 
        switch (up->port.iotype) {
@@ -318,6 +321,13 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset)
                return __raw_readl(up->port.membase + offset);
 #endif
 
+       case UPIO_TSI:
+               if (offset == UART_IIR) {
+                       tmp = readl(up->port.membase + (UART_IIR & ~3));
+                       return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+               } else
+                       return readb(up->port.membase + offset);
+
        default:
                return inb(up->port.iobase + offset);
        }
@@ -347,6 +357,10 @@ serial_out(struct uart_8250_port *up, int offset, int value)
                __raw_writel(value, up->port.membase + offset);
                break;
 #endif
+       case UPIO_TSI:
+               if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+                       writeb(value, up->port.membase + offset);
+               break;
 
        default:
                outb(value, up->port.iobase + offset);
@@ -362,6 +376,40 @@ serial_out(struct uart_8250_port *up, int offset, int value)
 #define serial_inp(up, offset)         serial_in(up, offset)
 #define serial_outp(up, offset, value) serial_out(up, offset, value)
 
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_8250_port *up)
+{
+       return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
+{
+       serial_outp(up, UART_DLL, value & 0xff);
+       serial_outp(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_8250_port *up)
+{
+       if (up->port.iotype == UPIO_AU)
+               return __raw_readl(up->port.membase + 0x28);
+       else
+               return _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+       if (up->port.iotype == UPIO_AU)
+               __raw_writel(value, up->port.membase + 0x28);
+       else
+               _serial_dl_write(up, value);
+}
+#else
+#define serial_dl_read(up) _serial_dl_read(up)
+#define serial_dl_write(up, value) _serial_dl_write(up, value)
+#endif
 
 /*
  * For the 16C950
@@ -494,7 +542,8 @@ static void disable_rsa(struct uart_8250_port *up)
  */
 static int size_fifo(struct uart_8250_port *up)
 {
-       unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr;
+       unsigned char old_fcr, old_mcr, old_lcr;
+       unsigned short old_dl;
        int count;
 
        old_lcr = serial_inp(up, UART_LCR);
@@ -505,10 +554,8 @@ static int size_fifo(struct uart_8250_port *up)
                    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
        serial_outp(up, UART_MCR, UART_MCR_LOOP);
        serial_outp(up, UART_LCR, UART_LCR_DLAB);
-       old_dll = serial_inp(up, UART_DLL);
-       old_dlm = serial_inp(up, UART_DLM);
-       serial_outp(up, UART_DLL, 0x01);
-       serial_outp(up, UART_DLM, 0x00);
+       old_dl = serial_dl_read(up);
+       serial_dl_write(up, 0x0001);
        serial_outp(up, UART_LCR, 0x03);
        for (count = 0; count < 256; count++)
                serial_outp(up, UART_TX, count);
@@ -519,8 +566,7 @@ static int size_fifo(struct uart_8250_port *up)
        serial_outp(up, UART_FCR, old_fcr);
        serial_outp(up, UART_MCR, old_mcr);
        serial_outp(up, UART_LCR, UART_LCR_DLAB);
-       serial_outp(up, UART_DLL, old_dll);
-       serial_outp(up, UART_DLM, old_dlm);
+       serial_dl_write(up, old_dl);
        serial_outp(up, UART_LCR, old_lcr);
 
        return count;
@@ -750,8 +796,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 
                        serial_outp(up, UART_LCR, 0xE0);
 
-                       quot = serial_inp(up, UART_DLM) << 8;
-                       quot += serial_inp(up, UART_DLL);
+                       quot = serial_dl_read(up);
                        quot <<= 3;
 
                        status1 = serial_in(up, 0x04); /* EXCR1 */
@@ -759,8 +804,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
                        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_dl_write(up, quot);
 
                        serial_outp(up, UART_LCR, 0);
 
@@ -1134,7 +1178,7 @@ static void serial8250_enable_ms(struct uart_port *port)
 }
 
 static void
-receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
+receive_chars(struct uart_8250_port *up, int *status)
 {
        struct tty_struct *tty = up->port.info->tty;
        unsigned char ch, lsr = *status;
@@ -1192,7 +1236,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
                        else if (lsr & UART_LSR_FE)
                                flag = TTY_FRAME;
                }
-               if (uart_handle_sysrq_char(&up->port, ch, regs))
+               if (uart_handle_sysrq_char(&up->port, ch))
                        goto ignore_char;
 
                uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
@@ -1248,7 +1292,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 {
        unsigned int status = serial_in(up, UART_MSR);
 
-       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {
+       if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+           up->port.info != NULL) {
                if (status & UART_MSR_TERI)
                        up->port.icount.rng++;
                if (status & UART_MSR_DDSR)
@@ -1268,7 +1313,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
  * This handles the interrupt from one port.
  */
 static inline void
-serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
+serial8250_handle_port(struct uart_8250_port *up)
 {
        unsigned int status;
 
@@ -1279,7 +1324,7 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
        DEBUG_INTR("status = %x...", status);
 
        if (status & UART_LSR_DR)
-               receive_chars(up, &status, regs);
+               receive_chars(up, &status);
        check_modem_status(up);
        if (status & UART_LSR_THRE)
                transmit_chars(up);
@@ -1301,7 +1346,7 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
  * This means we need to loop through all ports. checking that they
  * don't have an interrupt pending.
  */
-static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
 {
        struct irq_info *i = dev_id;
        struct list_head *l, *end = NULL;
@@ -1320,7 +1365,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)) {
-                       serial8250_handle_port(up, regs);
+                       serial8250_handle_port(up);
 
                        handled = 1;
 
@@ -1371,7 +1416,7 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
 static int serial_link_irq_chain(struct uart_8250_port *up)
 {
        struct irq_info *i = irq_lists + up->port.irq;
-       int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
+       int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
 
        spin_lock_irq(&i->lock);
 
@@ -1420,7 +1465,7 @@ static void serial8250_timeout(unsigned long data)
 
        iir = serial_in(up, UART_IIR);
        if (!(iir & UART_IIR_NO_INT))
-               serial8250_handle_port(up, NULL);
+               serial8250_handle_port(up);
 
        timeout = up->port.timeout;
        timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@@ -1528,7 +1573,7 @@ static int serial8250_startup(struct uart_port *port)
 
        /*
         * Clear the FIFO buffers and disable them.
-        * (they will be reeanbled in set_termios())
+        * (they will be reenabled in set_termios())
         */
        serial8250_clear_fifos(up);
 
@@ -1715,6 +1760,14 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
        else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
                 baud == (port->uartclk/8))
                quot = 0x8002;
+       /*
+        * For 16C950s UART_TCR is used in combination with divisor==1
+        * to achieve baud rates up to baud_base*4.
+        */
+       else if ((port->type == PORT_16C950) &&
+                baud > (port->uartclk/16))
+               quot = 1;
+
        else
                quot = uart_get_divisor(port, baud);
 
@@ -1722,13 +1775,13 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
 }
 
 static void
-serial8250_set_termios(struct uart_port *port, struct termios *termios,
-                      struct termios *old)
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
        unsigned char cval, fcr = 0;
        unsigned long flags;
-       unsigned int baud, quot;
+       unsigned int baud, quot, max_baud;
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
@@ -1760,7 +1813,8 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
        /*
         * Ask the core to calculate the divisor for us.
         */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+       max_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16);
+       baud = uart_get_baud_rate(port, termios, old, 0, max_baud); 
        quot = serial8250_get_divisor(port, baud);
 
        /*
@@ -1796,6 +1850,19 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
         */
        spin_lock_irqsave(&up->port.lock, flags);
 
+       /* 
+        * 16C950 supports additional prescaler ratios between 1:16 and 1:4
+        * thus increasing max baud rate to uartclk/4.
+        */
+       if (up->port.type == PORT_16C950) {
+               if (baud == port->uartclk/4)
+                       serial_icr_write(up, UART_TCR, 0x4);
+               else if (baud == port->uartclk/8)
+                       serial_icr_write(up, UART_TCR, 0x8);
+               else
+                       serial_icr_write(up, UART_TCR, 0);
+       }
+       
        /*
         * Update the per-port timeout.
         */
@@ -1855,6 +1922,17 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
                serial_outp(up, UART_EFR, efr);
        }
 
+#ifdef CONFIG_ARCH_OMAP15XX
+       /* Workaround to enable 115200 baud on OMAP1510 internal ports */
+       if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
+               if (baud == 115200) {
+                       quot = 1;
+                       serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
+               } else
+                       serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
+       }
+#endif
+
        if (up->capabilities & UART_NATSEMI) {
                /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
                serial_outp(up, UART_LCR, 0xe0);
@@ -1862,8 +1940,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
                serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
        }
 
-       serial_outp(up, UART_DLL, quot & 0xff);         /* LS of divisor */
-       serial_outp(up, UART_DLM, quot >> 8);           /* MS of divisor */
+       serial_dl_write(up, quot);
 
        /*
         * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -1906,6 +1983,11 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
        int ret = 0;
 
        switch (up->port.iotype) {
+       case UPIO_AU:
+               size = 0x100000;
+               /* fall thru */
+       case UPIO_TSI:
+       case UPIO_MEM32:
        case UPIO_MEM:
                if (!up->port.mapbase)
                        break;
@@ -1938,6 +2020,11 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
        unsigned int size = 8 << up->port.regshift;
 
        switch (up->port.iotype) {
+       case UPIO_AU:
+               size = 0x100000;
+               /* fall thru */
+       case UPIO_TSI:
+       case UPIO_MEM32:
        case UPIO_MEM:
                if (!up->port.mapbase)
                        break;
@@ -1961,17 +2048,15 @@ static int serial8250_request_rsa_resource(struct uart_8250_port *up)
 {
        unsigned long start = UART_RSA_BASE << up->port.regshift;
        unsigned int size = 8 << up->port.regshift;
-       int ret = 0;
+       int ret = -EINVAL;
 
        switch (up->port.iotype) {
-       case UPIO_MEM:
-               ret = -EINVAL;
-               break;
-
        case UPIO_HUB6:
        case UPIO_PORT:
                start += up->port.iobase;
-               if (!request_region(start, size, "serial-rsa"))
+               if (request_region(start, size, "serial-rsa"))
+                       ret = 0;
+               else
                        ret = -EBUSY;
                break;
        }
@@ -1985,9 +2070,6 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up)
        unsigned int size = 8 << up->port.regshift;
 
        switch (up->port.iotype) {
-       case UPIO_MEM:
-               break;
-
        case UPIO_HUB6:
        case UPIO_PORT:
                release_region(up->port.iobase + offset, size);
@@ -2176,12 +2258,21 @@ 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 (--tmout &&
-                      ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+               while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
                        udelay(1);
+                       touch_nmi_watchdog();
+               }
        }
 }
 
+static void serial8250_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+       wait_for_xmitr(up, UART_LSR_THRE);
+       serial_out(up, UART_TX, ch);
+}
+
 /*
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
@@ -2192,11 +2283,21 @@ static void
 serial8250_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct uart_8250_port *up = &serial8250_ports[co->index];
+       unsigned long flags;
        unsigned int ier;
-       int i;
+       int locked = 1;
 
        touch_nmi_watchdog();
 
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               /* serial8250_handle_port() already took the lock */
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
+
        /*
         *      First save the IER then disable the interrupts
         */
@@ -2207,33 +2308,21 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
        else
                serial_out(up, UART_IER, 0);
 
-       /*
-        *      Now, do each character
-        */
-       for (i = 0; i < count; i++, s++) {
-               wait_for_xmitr(up, UART_LSR_THRE);
-
-               /*
-                *      Send the character out.
-                *      If a LF, also do CR...
-                */
-               serial_out(up, UART_TX, *s);
-               if (*s == 10) {
-                       wait_for_xmitr(up, UART_LSR_THRE);
-                       serial_out(up, UART_TX, 13);
-               }
-       }
+       uart_console_write(&up->port, s, count, serial8250_console_putchar);
 
        /*
         *      Finally, wait for transmitter to become empty
         *      and restore the IER
         */
        wait_for_xmitr(up, BOTH_EMPTY);
-       up->ier |= UART_IER_THRI;
-       serial_out(up, UART_IER, ier | UART_IER_THRI);
+       serial_out(up, UART_IER, ier);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
 }
 
-static int serial8250_console_setup(struct console *co, char *options)
+static int __init serial8250_console_setup(struct console *co, char *options)
 {
        struct uart_port *port;
        int baud = 9600;
@@ -2318,7 +2407,6 @@ int __init serial8250_start_console(struct uart_port *port, char *options)
 static struct uart_driver serial8250_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "serial",
-       .devfs_name             = "tts/",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
        .minor                  = 64,
@@ -2346,7 +2434,6 @@ int __init early_serial_setup(struct uart_port *port)
 /**
  *     serial8250_suspend_port - suspend one serial port
  *     @line:  serial line number
- *      @level: the level of port suspension, as per uart_suspend_port
  *
  *     Suspend one serial port.
  */
@@ -2358,7 +2445,6 @@ void serial8250_suspend_port(int line)
 /**
  *     serial8250_resume_port - resume one serial port
  *     @line:  serial line number
- *      @level: the level of port resumption, as per uart_resume_port
  *
  *     Resume one serial port.
  */