vserver 1.9.5.x5
[linux-2.6.git] / drivers / serial / serial_core.c
index 1ac6c9d..16c227d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
+#include <linux/delay.h>
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -162,8 +163,6 @@ static int uart_startup(struct uart_state *state, int init_hw)
                        return -ENOMEM;
 
                info->xmit.buf = (unsigned char *) page;
-               info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE;
-               init_MUTEX(&info->tmpbuf_sem);
                uart_circ_clear(&info->xmit);
        }
 
@@ -238,7 +237,6 @@ static void uart_shutdown(struct uart_state *state)
        if (info->xmit.buf) {
                free_page((unsigned long)info->xmit.buf);
                info->xmit.buf = NULL;
-               info->tmpbuf = NULL;
        }
 
        /*
@@ -450,53 +448,30 @@ __uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static inline int
-__uart_user_write(struct uart_port *port, struct circ_buf *circ,
-                 const unsigned char __user *buf, int count)
+static void uart_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       unsigned long flags;
-       int c, ret = 0;
-
-       if (down_interruptible(&port->info->tmpbuf_sem))
-               return -EINTR;
-
-       while (1) {
-               int c1;
-               c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
-               if (count < c)
-                       c = count;
-               if (c <= 0)
-                       break;
+       struct uart_state *state = tty->driver_data;
 
-               c -= copy_from_user(port->info->tmpbuf, buf, c);
-               if (!c) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       break;
-               }
-               spin_lock_irqsave(&port->lock, flags);
-               c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
-               if (c1 < c)
-                       c = c1;
-               memcpy(circ->buf + circ->head, port->info->tmpbuf, c);
-               circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
-               spin_unlock_irqrestore(&port->lock, flags);
-               buf += c;
-               count -= c;
-               ret += c;
-       }
-       up(&port->info->tmpbuf_sem);
+       __uart_put_char(state->port, &state->info->xmit, ch);
+}
 
-       return ret;
+static void uart_flush_chars(struct tty_struct *tty)
+{
+       uart_start(tty);
 }
 
-static inline int
-__uart_kern_write(struct uart_port *port, struct circ_buf *circ,
-                 const unsigned char *buf, int count)
+static int
+uart_write(struct tty_struct *tty, const unsigned char * buf, int count)
 {
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->port;
+       struct circ_buf *circ = &state->info->xmit;
        unsigned long flags;
        int c, ret = 0;
 
+       if (!circ->buf)
+               return 0;
+
        spin_lock_irqsave(&port->lock, flags);
        while (1) {
                c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
@@ -512,38 +487,6 @@ __uart_kern_write(struct uart_port *port, struct circ_buf *circ,
        }
        spin_unlock_irqrestore(&port->lock, flags);
 
-       return ret;
-}
-
-static void uart_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       struct uart_state *state = tty->driver_data;
-
-       __uart_put_char(state->port, &state->info->xmit, ch);
-}
-
-static void uart_flush_chars(struct tty_struct *tty)
-{
-       uart_start(tty);
-}
-
-static int
-uart_write(struct tty_struct *tty, int from_user, const unsigned char * buf,
-          int count)
-{
-       struct uart_state *state = tty->driver_data;
-       int ret;
-
-       if (!state->info->xmit.buf)
-               return 0;
-
-       if (from_user)
-               ret = __uart_user_write(state->port, &state->info->xmit,
-                               (const unsigned char __user *)buf, count);
-       else
-               ret = __uart_kern_write(state->port, &state->info->xmit,
-                                       buf, count);
-
        uart_start(tty);
        return ret;
 }
@@ -641,8 +584,10 @@ static int uart_get_info(struct uart_state *state,
        tmp.flags           = port->flags;
        tmp.xmit_fifo_size  = port->fifosize;
        tmp.baud_base       = port->uartclk / 16;
-       tmp.close_delay     = state->close_delay;
-       tmp.closing_wait    = state->closing_wait;
+       tmp.close_delay     = state->close_delay / 10;
+       tmp.closing_wait    = state->closing_wait == USF_CLOSING_WAIT_NONE ?
+                               ASYNC_CLOSING_WAIT_NONE :
+                               state->closing_wait / 10;
        tmp.custom_divisor  = port->custom_divisor;
        tmp.hub6            = port->hub6;
        tmp.io_type         = port->iotype;
@@ -660,8 +605,8 @@ 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;
-       unsigned int old_custom_divisor;
+       unsigned int change_irq, change_port, old_flags, closing_wait;
+       unsigned int old_custom_divisor, close_delay;
        int retval = 0;
 
        if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
@@ -672,6 +617,9 @@ static int uart_set_info(struct uart_state *state,
                new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
 
        new_serial.irq = irq_canonicalize(new_serial.irq);
+       close_delay = new_serial.close_delay * 10;
+       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                       USF_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
 
        /*
         * This semaphore protects state->count.  It is also
@@ -703,8 +651,8 @@ static int uart_set_info(struct uart_state *state,
                retval = -EPERM;
                if (change_irq || change_port ||
                    (new_serial.baud_base != port->uartclk / 16) ||
-                   (new_serial.close_delay != state->close_delay) ||
-                   (new_serial.closing_wait != state->closing_wait) ||
+                   (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))
                        goto exit;
@@ -808,8 +756,8 @@ static int uart_set_info(struct uart_state *state,
        port->flags            = (port->flags & ~UPF_CHANGE_MASK) |
                                 (new_serial.flags & UPF_CHANGE_MASK);
        port->custom_divisor   = new_serial.custom_divisor;
-       state->close_delay     = new_serial.close_delay * HZ / 100;
-       state->closing_wait    = new_serial.closing_wait * HZ / 100;
+       state->close_delay     = close_delay;
+       state->closing_wait    = closing_wait;
        port->fifosize         = new_serial.xmit_fifo_size;
        if (state->info->tty)
                state->info->tty->low_latency =
@@ -1248,7 +1196,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        tty->closing = 1;
 
        if (state->closing_wait != USF_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, state->closing_wait);
+               tty_wait_until_sent(tty, msecs_to_jiffies(state->closing_wait));
 
        /*
         * At this point, we stop accepting input.  To do this, we
@@ -1276,10 +1224,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        state->info->tty = NULL;
 
        if (state->info->blocked_open) {
-               if (state->close_delay) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(state->close_delay);
-               }
+               if (state->close_delay)
+                       msleep_interruptible(state->close_delay);
        } else if (!uart_console(port)) {
                uart_change_pm(state, 3);
        }
@@ -1343,8 +1289,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
         * we wait.
         */
        while (!port->ops->tx_empty(port)) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(char_time);
+               msleep_interruptible(jiffies_to_msecs(char_time));
                if (signal_pending(current))
                        break;
                if (time_after(jiffies, expire))
@@ -1901,10 +1846,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
                 * Wait for the transmitter to empty.
                 */
                while (!ops->tx_empty(port)) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(10*HZ/1000);
+                       msleep(10);
                }
-               set_current_state(TASK_RUNNING);
 
                ops->shutdown(port);
        }
@@ -1934,7 +1877,21 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
         * Re-enable the console device after suspending.
         */
        if (uart_console(port)) {
-               uart_change_speed(state, NULL);
+               struct termios termios;
+
+               /*
+                * First try to use the console cflag setting.
+                */
+               memset(&termios, 0, sizeof(struct termios));
+               termios.c_cflag = port->cons->cflag;
+
+               /*
+                * If that's unset, use the tty termios setting.
+                */
+               if (state->info && state->info->tty && termios.c_cflag == 0)
+                       termios = *state->info->tty->termios;
+
+               port->ops->set_termios(port, &termios, NULL);
                console_start(port->cons);
        }
 
@@ -2143,8 +2100,8 @@ int uart_register_driver(struct uart_driver *drv)
        for (i = 0; i < drv->nr; i++) {
                struct uart_state *state = drv->state + i;
 
-               state->close_delay     = 5 * HZ / 10;
-               state->closing_wait    = 30 * HZ;
+               state->close_delay     = 500;   /* .5 seconds */
+               state->closing_wait    = 30000; /* 30 seconds */
 
                init_MUTEX(&state->sem);
        }
@@ -2225,6 +2182,15 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
         */
        tty_register_device(drv->tty_driver, port->line, port->dev);
 
+       /*
+        * If this driver supports console, and it hasn't been
+        * successfully registered yet, try to re-register it.
+        * It may be that the port was not available.
+        */
+       if (port->type != PORT_UNKNOWN &&
+           port->cons && !(port->cons->flags & CON_ENABLED))
+               register_console(port->cons);
+
  out:
        up(&port_sem);