ide-cd: replace C code with call to ARRAY_SIZE() macro
[safe/jmp/linux-2.6] / drivers / serial / serial_core.c
index fcd7744..326020f 100644 (file)
@@ -22,7 +22,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/slab.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK(x...)  printk(x)
-#else
-#define DPRINTK(x...)  do { } while (0)
-#endif
-
 /*
  * This is used to lock changes in serial line configuration.
  */
 static DEFINE_MUTEX(port_mutex);
 
+/*
+ * lockdep: port->lock is initialized in two places, but we
+ *          want only one lock-class:
+ */
+static struct lock_class_key port_lock_key;
+
 #define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
 
 #define uart_users(state)      ((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
@@ -60,7 +58,7 @@ static DEFINE_MUTEX(port_mutex);
 #define uart_console(port)     (0)
 #endif
 
-static void uart_change_speed(struct uart_state *state, struct termios *old_termios);
+static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios);
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
 static void uart_change_pm(struct uart_state *state, int pm_state);
 
@@ -333,8 +331,8 @@ EXPORT_SYMBOL(uart_update_timeout);
  *     we're actually going to be using.
  */
 unsigned int
-uart_get_baud_rate(struct uart_port *port, struct termios *termios,
-                  struct termios *old, unsigned int min, unsigned int max)
+uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old, unsigned int min, unsigned int max)
 {
        unsigned int try, baud, altbaud = 38400;
        upf_t flags = port->flags & UPF_SPD_MASK;
@@ -416,11 +414,11 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
 EXPORT_SYMBOL(uart_get_divisor);
 
 static void
-uart_change_speed(struct uart_state *state, struct termios *old_termios)
+uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
 {
        struct tty_struct *tty = state->info->tty;
        struct uart_port *port = state->port;
-       struct termios *termios;
+       struct ktermios *termios;
 
        /*
         * If we have no tty, termios, or the port does not exist,
@@ -547,7 +545,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
                return;
        }
 
-       DPRINTK("uart_flush_buffer(%d) called\n", tty->index);
+       pr_debug("uart_flush_buffer(%d) called\n", tty->index);
 
        spin_lock_irqsave(&port->lock, flags);
        uart_circ_clear(&state->info->xmit);
@@ -667,19 +665,21 @@ static int uart_set_info(struct uart_state *state,
         */
        mutex_lock(&state->mutex);
 
-       change_irq  = new_serial.irq != port->irq;
+       change_irq  = !(port->flags & UPF_FIXED_PORT)
+               && new_serial.irq != port->irq;
 
        /*
         * Since changing the 'type' of the port changes its resource
         * allocations, we should treat type changes the same as
         * IO port changes.
         */
-       change_port = new_port != port->iobase ||
-                     (unsigned long)new_serial.iomem_base != port->mapbase ||
-                     new_serial.hub6 != port->hub6 ||
-                     new_serial.io_type != port->iotype ||
-                     new_serial.iomem_reg_shift != port->regshift ||
-                     new_serial.type != port->type;
+       change_port = !(port->flags & UPF_FIXED_PORT)
+               && (new_port != port->iobase ||
+                   (unsigned long)new_serial.iomem_base != port->mapbase ||
+                   new_serial.hub6 != port->hub6 ||
+                   new_serial.io_type != port->iotype ||
+                   new_serial.iomem_reg_shift != port->regshift ||
+                   new_serial.type != port->type);
 
        old_flags = port->flags;
        new_flags = new_serial.flags;
@@ -691,7 +691,8 @@ static int uart_set_info(struct uart_state *state,
                    (new_serial.baud_base != port->uartclk / 16) ||
                    (close_delay != state->close_delay) ||
                    (closing_wait != state->closing_wait) ||
-                   (new_serial.xmit_fifo_size != port->fifosize) ||
+                   (new_serial.xmit_fifo_size &&
+                    new_serial.xmit_fifo_size != port->fifosize) ||
                    (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
                        goto exit;
                port->flags = ((port->flags & ~UPF_USR_MASK) |
@@ -786,17 +787,21 @@ static int uart_set_info(struct uart_state *state,
                         * We failed anyway.
                         */
                        retval = -EBUSY;
+                       goto exit;  // Added to return the correct error -Ram Gupta
                }
        }
 
-       port->irq              = new_serial.irq;
-       port->uartclk          = new_serial.baud_base * 16;
+       if (change_irq)
+               port->irq      = new_serial.irq;
+       if (!(port->flags & UPF_FIXED_PORT))
+               port->uartclk  = new_serial.baud_base * 16;
        port->flags            = (port->flags & ~UPF_CHANGE_MASK) |
                                 (new_flags & UPF_CHANGE_MASK);
        port->custom_divisor   = new_serial.custom_divisor;
        state->close_delay     = close_delay;
        state->closing_wait    = closing_wait;
-       port->fifosize         = new_serial.xmit_fifo_size;
+       if (new_serial.xmit_fifo_size)
+               port->fifosize = new_serial.xmit_fifo_size;
        if (state->info->tty)
                state->info->tty->low_latency =
                        (port->flags & UPF_LOW_LATENCY) ? 1 : 0;
@@ -1131,7 +1136,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
        return ret;
 }
 
-static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
        struct uart_state *state = tty->driver_data;
        unsigned long flags;
@@ -1212,7 +1217,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 
        port = state->port;
 
-       DPRINTK("uart_close(%d) called\n", port->line);
+       pr_debug("uart_close(%d) called\n", port->line);
 
        mutex_lock(&state->mutex);
 
@@ -1331,7 +1336,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
 
        expire = jiffies + timeout;
 
-       DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+       pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
                port->line, jiffies, expire);
 
        /*
@@ -1360,7 +1365,7 @@ static void uart_hangup(struct tty_struct *tty)
        struct uart_state *state = tty->driver_data;
 
        BUG_ON(!kernel_locked());
-       DPRINTK("uart_hangup(%d)\n", state->port->line);
+       pr_debug("uart_hangup(%d)\n", state->port->line);
 
        mutex_lock(&state->mutex);
        if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
@@ -1500,26 +1505,23 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
 static struct uart_state *uart_get(struct uart_driver *drv, int line)
 {
        struct uart_state *state;
+       int ret = 0;
 
-       mutex_lock(&port_mutex);
        state = drv->state + line;
        if (mutex_lock_interruptible(&state->mutex)) {
-               state = ERR_PTR(-ERESTARTSYS);
-               goto out;
+               ret = -ERESTARTSYS;
+               goto err;
        }
 
        state->count++;
-       if (!state->port) {
-               state->count--;
-               mutex_unlock(&state->mutex);
-               state = ERR_PTR(-ENXIO);
-               goto out;
+       if (!state->port || state->port->flags & UPF_DEAD) {
+               ret = -ENXIO;
+               goto err_unlock;
        }
 
        if (!state->info) {
-               state->info = kmalloc(sizeof(struct uart_info), GFP_KERNEL);
+               state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
                if (state->info) {
-                       memset(state->info, 0, sizeof(struct uart_info));
                        init_waitqueue_head(&state->info->open_wait);
                        init_waitqueue_head(&state->info->delta_msr_wait);
 
@@ -1531,15 +1533,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
                        tasklet_init(&state->info->tlet, uart_tasklet_action,
                                     (unsigned long)state);
                } else {
-                       state->count--;
-                       mutex_unlock(&state->mutex);
-                       state = ERR_PTR(-ENOMEM);
+                       ret = -ENOMEM;
+                       goto err_unlock;
                }
        }
-
- out:
-       mutex_unlock(&port_mutex);
        return state;
+
+ err_unlock:
+       state->count--;
+       mutex_unlock(&state->mutex);
+ err:
+       return ERR_PTR(ret);
 }
 
 /*
@@ -1559,7 +1563,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        int retval, line = tty->index;
 
        BUG_ON(!kernel_locked());
-       DPRINTK("uart_open(%d) called\n", line);
+       pr_debug("uart_open(%d) called\n", line);
 
        /*
         * tty->driver->num won't change, so we won't fail here with
@@ -1652,19 +1656,20 @@ static const char *uart_type(struct uart_port *port)
 static int uart_line_info(char *buf, struct uart_driver *drv, int i)
 {
        struct uart_state *state = drv->state + i;
+       int pm_state;
        struct uart_port *port = state->port;
        char stat_buf[32];
        unsigned int status;
-       int ret;
+       int mmio, ret;
 
        if (!port)
                return 0;
 
+       mmio = port->iotype >= UPIO_MEM;
        ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d",
                        port->line, uart_type(port),
-                       port->iotype == UPIO_MEM ? "mmio:0x" : "port:",
-                       port->iotype == UPIO_MEM ? port->mapbase :
-                                               (unsigned long) port->iobase,
+                       mmio ? "mmio:0x" : "port:",
+                       mmio ? port->mapbase : (unsigned long) port->iobase,
                        port->irq);
 
        if (port->type == PORT_UNKNOWN) {
@@ -1674,9 +1679,16 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
 
        if(capable(CAP_SYS_ADMIN))
        {
+               mutex_lock(&state->mutex);
+               pm_state = state->pm_state;
+               if (pm_state)
+                       uart_change_pm(state, 0);
                spin_lock_irq(&port->lock);
                status = port->ops->get_mctrl(port);
                spin_unlock_irq(&port->lock);
+               if (pm_state)
+                       uart_change_pm(state, pm_state);
+               mutex_unlock(&state->mutex);
 
                ret += sprintf(buf + ret, " tx:%d rx:%d",
                                port->icount.tx, port->icount.rx);
@@ -1858,7 +1870,7 @@ int __init
 uart_set_options(struct uart_port *port, struct console *co,
                 int baud, int parity, int bits, int flow)
 {
-       struct termios termios;
+       struct ktermios termios;
        int i;
 
        /*
@@ -1866,8 +1878,9 @@ uart_set_options(struct uart_port *port, struct console *co,
         * early.
         */
        spin_lock_init(&port->lock);
+       lockdep_set_class(&port->lock, &port_lock_key);
 
-       memset(&termios, 0, sizeof(struct termios));
+       memset(&termios, 0, sizeof(struct ktermios));
 
        termios.c_cflag = CREAD | HUPCL | CLOCAL;
 
@@ -1907,9 +1920,12 @@ uart_set_options(struct uart_port *port, struct console *co,
 static void uart_change_pm(struct uart_state *state, int pm_state)
 {
        struct uart_port *port = state->port;
-       if (port->ops->pm)
-               port->ops->pm(port, pm_state, state->pm_state);
-       state->pm_state = pm_state;
+
+       if (state->pm_state != pm_state) {
+               if (port->ops->pm)
+                       port->ops->pm(port, pm_state, state->pm_state);
+               state->pm_state = pm_state;
+       }
 }
 
 int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
@@ -1918,9 +1934,19 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
 
        mutex_lock(&state->mutex);
 
+#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
+       if (uart_console(port)) {
+               mutex_unlock(&state->mutex);
+               return 0;
+       }
+#endif
+
        if (state->info && state->info->flags & UIF_INITIALIZED) {
                const struct uart_ops *ops = port->ops;
 
+               state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
+                                    | UIF_SUSPENDED;
+
                spin_lock_irq(&port->lock);
                ops->stop_tx(port);
                ops->set_mctrl(port, 0);
@@ -1956,18 +1982,25 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
 
        mutex_lock(&state->mutex);
 
+#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
+       if (uart_console(port)) {
+               mutex_unlock(&state->mutex);
+               return 0;
+       }
+#endif
+
        uart_change_pm(state, 0);
 
        /*
         * Re-enable the console device after suspending.
         */
        if (uart_console(port)) {
-               struct termios termios;
+               struct ktermios termios;
 
                /*
                 * First try to use the console cflag setting.
                 */
-               memset(&termios, 0, sizeof(struct termios));
+               memset(&termios, 0, sizeof(struct ktermios));
                termios.c_cflag = port->cons->cflag;
 
                /*
@@ -1980,7 +2013,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                console_start(port->cons);
        }
 
-       if (state->info && state->info->flags & UIF_INITIALIZED) {
+       if (state->info && state->info->flags & UIF_SUSPENDED) {
                const struct uart_ops *ops = port->ops;
                int ret;
 
@@ -1992,15 +2025,17 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                        ops->set_mctrl(port, port->mctrl);
                        ops->start_tx(port);
                        spin_unlock_irq(&port->lock);
+                       state->info->flags |= UIF_INITIALIZED;
                } else {
                        /*
                         * Failed to resume - maybe hardware went away?
                         * Clear the "initialized" flag so we won't try
                         * to call the low level drivers shutdown method.
                         */
-                       state->info->flags &= ~UIF_INITIALIZED;
                        uart_shutdown(state);
                }
+
+               state->info->flags &= ~UIF_SUSPENDED;
        }
 
        mutex_unlock(&state->mutex);
@@ -2025,6 +2060,8 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
        case UPIO_MEM:
        case UPIO_MEM32:
        case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_DWAPB:
                snprintf(address, sizeof(address),
                         "MMIO 0x%lx", port->mapbase);
                break;
@@ -2068,6 +2105,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 
                uart_report_port(drv, port);
 
+               /* Power up port for set_mctrl() */
+               uart_change_pm(state, 0);
+
                /*
                 * Ensure that the modem control lines are de-activated.
                 * We probably don't need a spinlock around this, but
@@ -2085,46 +2125,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
        }
 }
 
-/*
- * This reverses the effects of uart_configure_port, hanging up the
- * port before removal.
- */
-static void
-uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
-{
-       struct uart_port *port = state->port;
-       struct uart_info *info = state->info;
-
-       if (info && info->tty)
-               tty_vhangup(info->tty);
-
-       mutex_lock(&state->mutex);
-
-       state->info = NULL;
-
-       /*
-        * Free the port IO and memory resources, if any.
-        */
-       if (port->type != PORT_UNKNOWN)
-               port->ops->release_port(port);
-
-       /*
-        * Indicate that there isn't a port here anymore.
-        */
-       port->type = PORT_UNKNOWN;
-
-       /*
-        * Kill the tasklet, and free resources.
-        */
-       if (info) {
-               tasklet_kill(&info->tlet);
-               kfree(info);
-       }
-
-       mutex_unlock(&state->mutex);
-}
-
-static struct tty_operations uart_ops = {
+static const struct tty_operations uart_ops = {
        .open           = uart_open,
        .close          = uart_close,
        .write          = uart_write,
@@ -2174,13 +2175,11 @@ int uart_register_driver(struct uart_driver *drv)
         * Maybe we should be using a slab cache for this, especially if
         * we have a large number of ports to handle.
         */
-       drv->state = kmalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
+       drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
        retval = -ENOMEM;
        if (!drv->state)
                goto out;
 
-       memset(drv->state, 0, sizeof(struct uart_state) * drv->nr);
-
        normal  = alloc_tty_driver(drv->nr);
        if (!normal)
                goto out;
@@ -2189,7 +2188,6 @@ int uart_register_driver(struct uart_driver *drv)
 
        normal->owner           = drv->owner;
        normal->driver_name     = drv->driver_name;
-       normal->devfs_name      = drv->devfs_name;
        normal->name            = drv->dev_name;
        normal->major           = drv->major;
        normal->minor_start     = drv->minor;
@@ -2197,7 +2195,8 @@ int uart_register_driver(struct uart_driver *drv)
        normal->subtype         = SERIAL_TYPE_NORMAL;
        normal->init_termios    = tty_std_termios;
        normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
+       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        normal->driver_state    = drv;
        tty_set_operations(normal, &uart_ops);
 
@@ -2270,6 +2269,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
        state = drv->state + port->line;
 
        mutex_lock(&port_mutex);
+       mutex_lock(&state->mutex);
        if (state->port) {
                ret = -EINVAL;
                goto out;
@@ -2284,8 +2284,10 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
         * If this port is a console, then the spinlock is already
         * initialised.
         */
-       if (!(uart_console(port) && (port->cons->flags & CON_ENABLED)))
+       if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
                spin_lock_init(&port->lock);
+               lockdep_set_class(&port->lock, &port_lock_key);
+       }
 
        uart_configure_port(drv, state, port);
 
@@ -2304,7 +2306,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
            port->cons && !(port->cons->flags & CON_ENABLED))
                register_console(port->cons);
 
+       /*
+        * Ensure UPF_DEAD is not set.
+        */
+       port->flags &= ~UPF_DEAD;
+
  out:
+       mutex_unlock(&state->mutex);
        mutex_unlock(&port_mutex);
 
        return ret;
@@ -2322,6 +2330,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
 int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
 {
        struct uart_state *state = drv->state + port->line;
+       struct uart_info *info;
 
        BUG_ON(in_interrupt());
 
@@ -2332,11 +2341,48 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
        mutex_lock(&port_mutex);
 
        /*
-        * Remove the devices from devfs
+        * Mark the port "dead" - this prevents any opens from
+        * succeeding while we shut down the port.
+        */
+       mutex_lock(&state->mutex);
+       port->flags |= UPF_DEAD;
+       mutex_unlock(&state->mutex);
+
+       /*
+        * Remove the devices from the tty layer
         */
        tty_unregister_device(drv->tty_driver, port->line);
 
-       uart_unconfigure_port(drv, state);
+       info = state->info;
+       if (info && info->tty)
+               tty_vhangup(info->tty);
+
+       /*
+        * All users of this port should now be disconnected from
+        * this driver, and the port shut down.  We should be the
+        * only thread fiddling with this port from now on.
+        */
+       state->info = NULL;
+
+       /*
+        * Free the port IO and memory resources, if any.
+        */
+       if (port->type != PORT_UNKNOWN)
+               port->ops->release_port(port);
+
+       /*
+        * Indicate that there isn't a port here anymore.
+        */
+       port->type = PORT_UNKNOWN;
+
+       /*
+        * Kill the tasklet, and free resources.
+        */
+       if (info) {
+               tasklet_kill(&info->tlet);
+               kfree(info);
+       }
+
        state->port = NULL;
        mutex_unlock(&port_mutex);
 
@@ -2358,6 +2404,10 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
                return (port1->iobase == port2->iobase) &&
                       (port1->hub6   == port2->hub6);
        case UPIO_MEM:
+       case UPIO_MEM32:
+       case UPIO_AU:
+       case UPIO_TSI:
+       case UPIO_DWAPB:
                return (port1->mapbase == port2->mapbase);
        }
        return 0;