This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / char / amiserial.c
index 1dc4259..f11cf4e 100644 (file)
@@ -32,7 +32,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/delay.h>
 
 #undef SERIAL_PARANOIA_CHECK
 #define SERIAL_DO_RESTART
@@ -84,13 +83,14 @@ static char *serial_version = "4.30";
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <asm/setup.h>
 
 #include <asm/system.h>
 
 #include <asm/irq.h>
+#include <asm/bitops.h>
 
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
@@ -645,7 +645,7 @@ static int startup(struct async_struct * info)
        /*
         * and set the speed of the serial port
         */
-       change_speed(info, NULL);
+       change_speed(info, 0);
 
        info->flags |= ASYNC_INITIALIZED;
        local_irq_restore(flags);
@@ -691,7 +691,7 @@ static void shutdown(struct async_struct * info)
 
        if (info->xmit.buf) {
                free_page((unsigned long) info->xmit.buf);
-               info->xmit.buf = NULL;
+               info->xmit.buf = 0;
        }
 
        info->IER = 0;
@@ -907,7 +907,8 @@ static void rs_flush_chars(struct tty_struct *tty)
        local_irq_restore(flags);
 }
 
-static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int rs_write(struct tty_struct * tty, int from_user,
+                   const unsigned char *buf, int count)
 {
        int     c, ret = 0;
        struct async_struct *info = (struct async_struct *)tty->driver_data;
@@ -920,25 +921,57 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
                return 0;
 
        local_save_flags(flags);
-       local_irq_disable();
-       while (1) {
-               c = CIRC_SPACE_TO_END(info->xmit.head,
-                                     info->xmit.tail,
-                                     SERIAL_XMIT_SIZE);
-               if (count < c)
-                       c = count;
-               if (c <= 0) {
-                       break;
+       if (from_user) {
+               down(&tmp_buf_sem);
+               while (1) {
+                       int c1;
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+                       if (count < c)
+                               c = count;
+
+                       c -= copy_from_user(tmp_buf, buf, c);
+                       if (!c) {
+                               if (!ret)
+                                       ret = -EFAULT;
+                               break;
+                       }
+                       local_irq_disable();
+                       c1 = CIRC_SPACE_TO_END(info->xmit.head,
+                                              info->xmit.tail,
+                                              SERIAL_XMIT_SIZE);
+                       if (c1 < c)
+                               c = c1;
+                       memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+                       info->xmit.head = ((info->xmit.head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       local_irq_restore(flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
                }
-               memcpy(info->xmit.buf + info->xmit.head, buf, c);
-               info->xmit.head = ((info->xmit.head + c) &
-                                  (SERIAL_XMIT_SIZE-1));
-               buf += c;
-               count -= c;
-               ret += c;
+               up(&tmp_buf_sem);
+       } else {
+               local_irq_disable();
+               while (1) {
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+                       if (count < c)
+                               c = count;
+                       if (c <= 0) {
+                               break;
+                       }
+                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
+                       info->xmit.head = ((info->xmit.head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               local_irq_restore(flags);
        }
-       local_irq_restore(flags);
-
        if (info->xmit.head != info->xmit.tail
            && !tty->stopped
            && !tty->hw_stopped
@@ -1172,7 +1205,7 @@ check_and_exit:
                                info->tty->alt_speed = 230400;
                        if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
                                info->tty->alt_speed = 460800;
-                       change_speed(info, NULL);
+                       change_speed(info, 0);
                }
        } else
                retval = startup(info);
@@ -1527,10 +1560,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
-       info->tty = NULL;
+       info->tty = 0;
        if (info->blocked_open) {
                if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(info->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
@@ -1588,7 +1622,8 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
                printk("serdatr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
-               msleep_interruptible(jiffies_to_msecs(char_time));
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(char_time);
                if (signal_pending(current))
                        break;
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
@@ -1618,7 +1653,7 @@ static void rs_hangup(struct tty_struct *tty)
        info->event = 0;
        state->count = 0;
        info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = NULL;
+       info->tty = 0;
        wake_up_interruptible(&info->open_wait);
 }
 
@@ -1874,7 +1909,7 @@ static inline int line_info(char *buf, struct serial_state *state)
                info->magic = SERIAL_MAGIC;
                info->flags = state->flags;
                info->quot = 0;
-               info->tty = NULL;
+               info->tty = 0;
        }
        local_irq_save(flags);
        status = ciab.pra;