serial: fix parisc boot hang
[cascardo/linux.git] / drivers / tty / serial / serial_core.c
index eaeb9a0..984605b 100644 (file)
@@ -61,7 +61,7 @@ static void uart_port_shutdown(struct tty_port *port);
 
 static int uart_dcd_enabled(struct uart_port *uport)
 {
-       return uport->status & UPSTAT_DCD_ENABLE;
+       return !!(uport->status & UPSTAT_DCD_ENABLE);
 }
 
 /*
@@ -436,7 +436,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
 
 EXPORT_SYMBOL(uart_get_divisor);
 
-/* FIXME: Consistent locking policy */
+/* Caller holds port mutex */
 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
                                        struct ktermios *old_termios)
 {
@@ -537,9 +537,10 @@ static int uart_write(struct tty_struct *tty,
                count -= c;
                ret += c;
        }
+
+       __uart_start(tty);
        spin_unlock_irqrestore(&port->lock, flags);
 
-       uart_start(tty);
        return ret;
 }
 
@@ -618,7 +619,7 @@ static void uart_throttle(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
        struct uart_port *port = state->uart_port;
-       uint32_t mask = 0;
+       upf_t mask = 0;
 
        if (I_IXOFF(tty))
                mask |= UPF_SOFT_FLOW;
@@ -641,7 +642,7 @@ static void uart_unthrottle(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
        struct uart_port *port = state->uart_port;
-       uint32_t mask = 0;
+       upf_t mask = 0;
 
        if (I_IXOFF(tty))
                mask |= UPF_SOFT_FLOW;
@@ -1151,6 +1152,47 @@ static int uart_get_icount(struct tty_struct *tty,
        return 0;
 }
 
+static int uart_get_rs485_config(struct uart_port *port,
+                        struct serial_rs485 __user *rs485)
+{
+       unsigned long flags;
+       struct serial_rs485 aux;
+
+       spin_lock_irqsave(&port->lock, flags);
+       aux = port->rs485;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (copy_to_user(rs485, &aux, sizeof(aux)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int uart_set_rs485_config(struct uart_port *port,
+                        struct serial_rs485 __user *rs485_user)
+{
+       struct serial_rs485 rs485;
+       int ret;
+       unsigned long flags;
+
+       if (!port->rs485_config)
+               return -ENOIOCTLCMD;
+
+       if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user)))
+               return -EFAULT;
+
+       spin_lock_irqsave(&port->lock, flags);
+       ret = port->rs485_config(port, &rs485);
+       spin_unlock_irqrestore(&port->lock, flags);
+       if (ret)
+               return ret;
+
+       if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485)))
+               return -EFAULT;
+
+       return 0;
+}
+
 /*
  * Called via sys_ioctl.  We can use spin_lock_irq() here.
  */
@@ -1173,11 +1215,15 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
                break;
 
        case TIOCSSERIAL:
+               down_write(&tty->termios_rwsem);
                ret = uart_set_info_user(tty, state, uarg);
+               up_write(&tty->termios_rwsem);
                break;
 
        case TIOCSERCONFIG:
+               down_write(&tty->termios_rwsem);
                ret = uart_do_autoconfig(tty, state);
+               up_write(&tty->termios_rwsem);
                break;
 
        case TIOCSERGWILD: /* obsolete */
@@ -1217,11 +1263,19 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
         * All these rely on hardware being present and need to be
         * protected against the tty being hung up.
         */
+
        switch (cmd) {
        case TIOCSERGETLSR: /* Get line status register */
                ret = uart_get_lsr_info(tty, state, uarg);
                break;
 
+       case TIOCGRS485:
+               ret = uart_get_rs485_config(state->uart_port, uarg);
+               break;
+
+       case TIOCSRS485:
+               ret = uart_set_rs485_config(state->uart_port, uarg);
+               break;
        default: {
                struct uart_port *uport = state->uart_port;
                if (uport->ops->ioctl)
@@ -1240,8 +1294,11 @@ static void uart_set_ldisc(struct tty_struct *tty)
        struct uart_state *state = tty->driver_data;
        struct uart_port *uport = state->uart_port;
 
-       if (uport->ops->set_ldisc)
-               uport->ops->set_ldisc(uport, tty->termios.c_line);
+       if (uport->ops->set_ldisc) {
+               mutex_lock(&state->port.mutex);
+               uport->ops->set_ldisc(uport, &tty->termios);
+               mutex_unlock(&state->port.mutex);
+       }
 }
 
 static void uart_set_termios(struct tty_struct *tty,
@@ -1278,7 +1335,9 @@ static void uart_set_termios(struct tty_struct *tty,
                return;
        }
 
+       mutex_lock(&state->port.mutex);
        uart_change_speed(tty, state, old_termios);
+       mutex_unlock(&state->port.mutex);
        /* reload cflag from termios; port driver may have overriden flags */
        cflag = tty->termios.c_cflag;
 
@@ -1331,8 +1390,16 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        struct uart_port *uport;
        unsigned long flags;
 
-       if (!state)
+       if (!state) {
+               struct uart_driver *drv = tty->driver->driver_state;
+
+               state = drv->state + tty->index;
+               port = &state->port;
+               spin_lock_irq(&port->lock);
+               --port->count;
+               spin_unlock_irq(&port->lock);
                return;
+       }
 
        uport = state->uart_port;
        port = &state->port;
@@ -1361,10 +1428,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 
        mutex_lock(&port->mutex);
        uart_shutdown(tty, state);
-       uart_flush_buffer(tty);
-
-       tty_ldisc_flush(tty);
-
        tty_port_tty_set(port, NULL);
        tty->closing = 0;
        spin_lock_irqsave(&port->lock, flags);
@@ -1372,8 +1435,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        if (port->blocked_open) {
                spin_unlock_irqrestore(&port->lock, flags);
                if (port->close_delay)
-                       msleep_interruptible(
-                                       jiffies_to_msecs(port->close_delay));
+                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
                spin_lock_irqsave(&port->lock, flags);
        } else if (!uart_console(uport)) {
                spin_unlock_irqrestore(&port->lock, flags);
@@ -1391,6 +1453,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        wake_up_interruptible(&port->close_wait);
 
        mutex_unlock(&port->mutex);
+
+       tty_ldisc_flush(tty);
 }
 
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
@@ -1552,6 +1616,10 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
 
        pr_debug("uart_open(%d) called\n", line);
 
+       spin_lock_irq(&port->lock);
+       ++port->count;
+       spin_unlock_irq(&port->lock);
+
        /*
         * We take the semaphore here to guarantee that we won't be re-entered
         * while allocating the state structure, or while we request any IRQs
@@ -1564,17 +1632,11 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
                goto end;
        }
 
-       port->count++;
        if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
                retval = -ENXIO;
-               goto err_dec_count;
+               goto err_unlock;
        }
 
-       /*
-        * Once we set tty->driver_data here, we are guaranteed that
-        * uart_close() will decrement the driver module use count.
-        * Any failures from here onwards should not touch the count.
-        */
        tty->driver_data = state;
        state->uart_port->state = state;
        state->port.low_latency =
@@ -1595,8 +1657,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
 
 end:
        return retval;
-err_dec_count:
-       port->count--;
+err_unlock:
        mutex_unlock(&port->mutex);
        goto end;
 }
@@ -2092,6 +2153,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
                break;
        case UPIO_MEM:
        case UPIO_MEM32:
+       case UPIO_MEM32BE:
        case UPIO_AU:
        case UPIO_TSI:
                snprintf(address, sizeof(address),
@@ -2102,7 +2164,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
                break;
        }
 
-       dev_info(port->dev, "%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
+       printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
+              port->dev ? dev_name(port->dev) : "",
+              port->dev ? ": " : "",
               drv->dev_name,
               drv->tty_driver->name_base + port->line,
               address, port->irq, port->uartclk / 16, uart_type(port));
@@ -2339,8 +2403,6 @@ int uart_register_driver(struct uart_driver *drv)
 
                tty_port_init(port);
                port->ops = &uart_port_ops;
-               port->close_delay     = HZ / 2; /* .5 seconds */
-               port->closing_wait    = 30 * HZ;/* 30 seconds */
        }
 
        retval = tty_register_driver(normal);
@@ -2589,11 +2651,12 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
                goto out;
        }
 
+       /* Link the port to the driver state table and vice versa */
        state->uart_port = uport;
-       state->pm_state = UART_PM_STATE_UNDEFINED;
+       uport->state = state;
 
+       state->pm_state = UART_PM_STATE_UNDEFINED;
        uport->cons = drv->cons;
-       uport->state = state;
 
        /*
         * If this port is a console, then the spinlock is already
@@ -2736,6 +2799,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
                       (port1->hub6   == port2->hub6);
        case UPIO_MEM:
        case UPIO_MEM32:
+       case UPIO_MEM32BE:
        case UPIO_AU:
        case UPIO_TSI:
                return (port1->mapbase == port2->mapbase);