[PATCH] sh: sh-sci clock framework updates
[safe/jmp/linux-2.6] / drivers / serial / serial_core.c
index 0745ce7..0717abf 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -47,7 +48,7 @@
 /*
  * This is used to lock changes in serial line configuration.
  */
-static DECLARE_MUTEX(port_sem);
+static DEFINE_MUTEX(port_mutex);
 
 #define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
 
@@ -209,33 +210,45 @@ static void uart_shutdown(struct uart_state *state)
        struct uart_info *info = state->info;
        struct uart_port *port = state->port;
 
-       if (!(info->flags & UIF_INITIALIZED))
-               return;
-
        /*
-        * Turn off DTR and RTS early.
+        * Set the TTY IO error marker
         */
-       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
-               uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
 
-       /*
-        * clear delta_msr_wait queue to avoid mem leaks: we may free
-        * the irq here so the queue might never be woken up.  Note
-        * that we won't end up waiting on delta_msr_wait again since
-        * any outstanding file descriptors should be pointing at
-        * hung_up_tty_fops now.
-        */
-       wake_up_interruptible(&info->delta_msr_wait);
+       if (info->flags & UIF_INITIALIZED) {
+               info->flags &= ~UIF_INITIALIZED;
 
-       /*
-        * Free the IRQ and disable the port.
-        */
-       port->ops->shutdown(port);
+               /*
+                * Turn off DTR and RTS early.
+                */
+               if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+                       uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+               /*
+                * clear delta_msr_wait queue to avoid mem leaks: we may free
+                * the irq here so the queue might never be woken up.  Note
+                * that we won't end up waiting on delta_msr_wait again since
+                * any outstanding file descriptors should be pointing at
+                * hung_up_tty_fops now.
+                */
+               wake_up_interruptible(&info->delta_msr_wait);
+
+               /*
+                * Free the IRQ and disable the port.
+                */
+               port->ops->shutdown(port);
+
+               /*
+                * Ensure that the IRQ handler isn't running on another CPU.
+                */
+               synchronize_irq(port->irq);
+       }
 
        /*
-        * Ensure that the IRQ handler isn't running on another CPU.
+        * kill off our tasklet
         */
-       synchronize_irq(port->irq);
+       tasklet_kill(&info->tlet);
 
        /*
         * Free the transmit buffer page.
@@ -244,15 +257,6 @@ static void uart_shutdown(struct uart_state *state)
                free_page((unsigned long)info->xmit.buf);
                info->xmit.buf = NULL;
        }
-
-       /*
-        * kill off our tasklet
-        */
-       tasklet_kill(&info->tlet);
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-       info->flags &= ~UIF_INITIALIZED;
 }
 
 /**
@@ -328,7 +332,7 @@ uart_get_baud_rate(struct uart_port *port, struct termios *termios,
                   struct termios *old, unsigned int min, unsigned int max)
 {
        unsigned int try, baud, altbaud = 38400;
-       unsigned int flags = port->flags & UPF_SPD_MASK;
+       upf_t flags = port->flags & UPF_SPD_MASK;
 
        if (flags == UPF_SPD_HI)
                altbaud = 57600;
@@ -611,8 +615,9 @@ static int uart_set_info(struct uart_state *state,
        struct serial_struct new_serial;
        struct uart_port *port = state->port;
        unsigned long new_port;
-       unsigned int change_irq, change_port, old_flags, closing_wait;
+       unsigned int change_irq, change_port, closing_wait;
        unsigned int old_custom_divisor, close_delay;
+       upf_t old_flags, new_flags;
        int retval = 0;
 
        if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
@@ -634,7 +639,7 @@ static int uart_set_info(struct uart_state *state,
         * module insertion/removal doesn't change anything
         * under us.
         */
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        change_irq  = new_serial.irq != port->irq;
 
@@ -651,6 +656,7 @@ static int uart_set_info(struct uart_state *state,
                      new_serial.type != port->type;
 
        old_flags = port->flags;
+       new_flags = new_serial.flags;
        old_custom_divisor = port->custom_divisor;
 
        if (!capable(CAP_SYS_ADMIN)) {
@@ -660,10 +666,10 @@ static int uart_set_info(struct uart_state *state,
                    (close_delay != state->close_delay) ||
                    (closing_wait != state->closing_wait) ||
                    (new_serial.xmit_fifo_size != port->fifosize) ||
-                   (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0))
+                   (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
                        goto exit;
                port->flags = ((port->flags & ~UPF_USR_MASK) |
-                              (new_serial.flags & UPF_USR_MASK));
+                              (new_flags & UPF_USR_MASK));
                port->custom_divisor = new_serial.custom_divisor;
                goto check_and_exit;
        }
@@ -760,7 +766,7 @@ static int uart_set_info(struct uart_state *state,
        port->irq              = new_serial.irq;
        port->uartclk          = new_serial.baud_base * 16;
        port->flags            = (port->flags & ~UPF_CHANGE_MASK) |
-                                (new_serial.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;
@@ -793,7 +799,7 @@ static int uart_set_info(struct uart_state *state,
        } else
                retval = uart_startup(state, 1);
  exit:
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        return retval;
 }
 
@@ -830,7 +836,7 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
        struct uart_port *port = state->port;
        int result = -EIO;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
        if ((!file || !tty_hung_up_p(file)) &&
            !(tty->flags & (1 << TTY_IO_ERROR))) {
                result = port->mctrl;
@@ -839,7 +845,7 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
                result |= port->ops->get_mctrl(port);
                spin_unlock_irq(&port->lock);
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        return result;
 }
@@ -852,13 +858,13 @@ uart_tiocmset(struct tty_struct *tty, struct file *file,
        struct uart_port *port = state->port;
        int ret = -EIO;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
        if ((!file || !tty_hung_up_p(file)) &&
            !(tty->flags & (1 << TTY_IO_ERROR))) {
                uart_update_mctrl(port, set, clear);
                ret = 0;
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        return ret;
 }
 
@@ -869,12 +875,12 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
 
        BUG_ON(!kernel_locked());
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (port->type != PORT_UNKNOWN)
                port->ops->break_ctl(port, break_state);
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 static int uart_do_autoconfig(struct uart_state *state)
@@ -890,7 +896,7 @@ static int uart_do_autoconfig(struct uart_state *state)
         * changing, and hence any extra opens of the port while
         * we're auto-configuring.
         */
-       if (down_interruptible(&state->sem))
+       if (mutex_lock_interruptible(&state->mutex))
                return -ERESTARTSYS;
 
        ret = -EBUSY;
@@ -916,7 +922,7 @@ static int uart_do_autoconfig(struct uart_state *state)
 
                ret = uart_startup(state, 1);
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        return ret;
 }
 
@@ -1070,7 +1076,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
        if (ret != -ENOIOCTLCMD)
                goto out;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (tty_hung_up_p(filp)) {
                ret = -EIO;
@@ -1094,7 +1100,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
        }
        }
  out_up:
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
  out:
        return ret;
 }
@@ -1182,7 +1188,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 
        DPRINTK("uart_close(%d) called\n", port->line);
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (tty_hung_up_p(filp))
                goto done;
@@ -1256,7 +1262,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        wake_up_interruptible(&state->info->open_wait);
 
  done:
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
@@ -1330,7 +1336,7 @@ static void uart_hangup(struct tty_struct *tty)
        BUG_ON(!kernel_locked());
        DPRINTK("uart_hangup(%d)\n", state->port->line);
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
        if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
                uart_flush_buffer(tty);
                uart_shutdown(state);
@@ -1340,7 +1346,7 @@ static void uart_hangup(struct tty_struct *tty)
                wake_up_interruptible(&state->info->open_wait);
                wake_up_interruptible(&state->info->delta_msr_wait);
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 /*
@@ -1437,14 +1443,15 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
                 * modem is ready for us.
                 */
                spin_lock_irq(&port->lock);
+               port->ops->enable_ms(port);
                mctrl = port->ops->get_mctrl(port);
                spin_unlock_irq(&port->lock);
                if (mctrl & TIOCM_CAR)
                        break;
 
-               up(&state->sem);
+               mutex_unlock(&state->mutex);
                schedule();
-               down(&state->sem);
+               mutex_lock(&state->mutex);
 
                if (signal_pending(current))
                        break;
@@ -1468,9 +1475,9 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
 {
        struct uart_state *state;
 
-       down(&port_sem);
+       mutex_lock(&port_mutex);
        state = drv->state + line;
-       if (down_interruptible(&state->sem)) {
+       if (mutex_lock_interruptible(&state->mutex)) {
                state = ERR_PTR(-ERESTARTSYS);
                goto out;
        }
@@ -1478,7 +1485,7 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
        state->count++;
        if (!state->port) {
                state->count--;
-               up(&state->sem);
+               mutex_unlock(&state->mutex);
                state = ERR_PTR(-ENXIO);
                goto out;
        }
@@ -1499,13 +1506,13 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
                                     (unsigned long)state);
                } else {
                        state->count--;
-                       up(&state->sem);
+                       mutex_unlock(&state->mutex);
                        state = ERR_PTR(-ENOMEM);
                }
        }
 
  out:
-       up(&port_sem);
+       mutex_unlock(&port_mutex);
        return state;
 }
 
@@ -1566,7 +1573,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        if (tty_hung_up_p(filp)) {
                retval = -EAGAIN;
                state->count--;
-               up(&state->sem);
+               mutex_unlock(&state->mutex);
                goto fail;
        }
 
@@ -1586,7 +1593,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
         */
        if (retval == 0)
                retval = uart_block_til_ready(filp, state);
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        /*
         * If this is the first open to succeed, adjust things to suit.
@@ -1776,7 +1783,7 @@ struct baud_rates {
        unsigned int cflag;
 };
 
-static struct baud_rates baud_rates[] = {
+static const struct baud_rates baud_rates[] = {
        { 921600, B921600 },
        { 460800, B460800 },
        { 230400, B230400 },
@@ -1862,10 +1869,10 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
 {
        struct uart_state *state = drv->state + port->line;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (state->info && state->info->flags & UIF_INITIALIZED) {
-               struct uart_ops *ops = port->ops;
+               const struct uart_ops *ops = port->ops;
 
                spin_lock_irq(&port->lock);
                ops->stop_tx(port);
@@ -1891,7 +1898,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
 
        uart_change_pm(state, 3);
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        return 0;
 }
@@ -1900,7 +1907,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
 {
        struct uart_state *state = drv->state + port->line;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        uart_change_pm(state, 0);
 
@@ -1927,18 +1934,29 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
        }
 
        if (state->info && state->info->flags & UIF_INITIALIZED) {
-               struct uart_ops *ops = port->ops;
+               const struct uart_ops *ops = port->ops;
+               int ret;
 
                ops->set_mctrl(port, 0);
-               ops->startup(port);
-               uart_change_speed(state, NULL);
-               spin_lock_irq(&port->lock);
-               ops->set_mctrl(port, port->mctrl);
-               ops->start_tx(port);
-               spin_unlock_irq(&port->lock);
+               ret = ops->startup(port);
+               if (ret == 0) {
+                       uart_change_speed(state, NULL);
+                       spin_lock_irq(&port->lock);
+                       ops->set_mctrl(port, port->mctrl);
+                       ops->start_tx(port);
+                       spin_unlock_irq(&port->lock);
+               } 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);
+               }
        }
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        return 0;
 }
@@ -1959,6 +1977,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
                break;
        case UPIO_MEM:
        case UPIO_MEM32:
+       case UPIO_AU:
                snprintf(address, sizeof(address),
                         "MMIO 0x%lx", port->mapbase);
                break;
@@ -2032,7 +2051,7 @@ uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
        if (info && info->tty)
                tty_vhangup(info->tty);
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        state->info = NULL;
 
@@ -2055,7 +2074,7 @@ uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
                kfree(info);
        }
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 static struct tty_operations uart_ops = {
@@ -2144,7 +2163,7 @@ int uart_register_driver(struct uart_driver *drv)
                state->close_delay     = 500;   /* .5 seconds */
                state->closing_wait    = 30000; /* 30 seconds */
 
-               init_MUTEX(&state->sem);
+               mutex_init(&state->mutex);
        }
 
        retval = tty_register_driver(normal);
@@ -2203,7 +2222,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
 
        state = drv->state + port->line;
 
-       down(&port_sem);
+       mutex_lock(&port_mutex);
        if (state->port) {
                ret = -EINVAL;
                goto out;
@@ -2239,7 +2258,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
                register_console(port->cons);
 
  out:
-       up(&port_sem);
+       mutex_unlock(&port_mutex);
 
        return ret;
 }
@@ -2263,7 +2282,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
                printk(KERN_ALERT "Removing wrong port: %p != %p\n",
                        state->port, port);
 
-       down(&port_sem);
+       mutex_lock(&port_mutex);
 
        /*
         * Remove the devices from devfs
@@ -2272,7 +2291,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
 
        uart_unconfigure_port(drv, state);
        state->port = NULL;
-       up(&port_sem);
+       mutex_unlock(&port_mutex);
 
        return 0;
 }
@@ -2292,7 +2311,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
                return (port1->iobase == port2->iobase) &&
                       (port1->hub6   == port2->hub6);
        case UPIO_MEM:
-               return (port1->membase == port2->membase);
+               return (port1->mapbase == port2->mapbase);
        }
        return 0;
 }