Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / s390 / char / sclp_tty.c
index 1035707..6cbf067 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kmod.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
@@ -112,46 +113,46 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file,
        switch (cmd) {
        case TIOCSCLPSHTAB:
                /* set width of horizontal tab  */
-               if (get_user(sclp_ioctls.htab, (unsigned short *) arg))
+               if (get_user(sclp_ioctls.htab, (unsigned short __user *) arg))
                        rc = -EFAULT;
                else
                        check = 1;
                break;
        case TIOCSCLPGHTAB:
                /* get width of horizontal tab  */
-               if (put_user(sclp_ioctls.htab, (unsigned short *) arg))
+               if (put_user(sclp_ioctls.htab, (unsigned short __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPSECHO:
                /* enable/disable echo of input */
-               if (get_user(sclp_ioctls.echo, (unsigned char *) arg))
+               if (get_user(sclp_ioctls.echo, (unsigned char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPGECHO:
                /* Is echo of input enabled ?  */
-               if (put_user(sclp_ioctls.echo, (unsigned char *) arg))
+               if (put_user(sclp_ioctls.echo, (unsigned char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPSCOLS:
                /* set number of columns for output  */
-               if (get_user(sclp_ioctls.columns, (unsigned short *) arg))
+               if (get_user(sclp_ioctls.columns, (unsigned short __user *) arg))
                        rc = -EFAULT;
                else
                        check = 1;
                break;
        case TIOCSCLPGCOLS:
                /* get number of columns for output  */
-               if (put_user(sclp_ioctls.columns, (unsigned short *) arg))
+               if (put_user(sclp_ioctls.columns, (unsigned short __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPSNL:
                /* enable/disable writing without final new line character  */
-               if (get_user(sclp_ioctls.final_nl, (signed char *) arg))
+               if (get_user(sclp_ioctls.final_nl, (signed char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPGNL:
                /* Is writing without final new line character enabled ?  */
-               if (put_user(sclp_ioctls.final_nl, (signed char *) arg))
+               if (put_user(sclp_ioctls.final_nl, (signed char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPSOBUF:
@@ -160,7 +161,7 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file,
                 * up to next 4kB boundary and stored as number of SCCBs
                 * (4kB Buffers) limitation: 256 x 4kB
                 */
-               if (get_user(obuf, (unsigned int *) arg) == 0) {
+               if (get_user(obuf, (unsigned int __user *) arg) == 0) {
                        if (obuf & 0xFFF)
                                sclp_ioctls.max_sccb = (obuf >> 12) + 1;
                        else
@@ -171,22 +172,22 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file,
        case TIOCSCLPGOBUF:
                /* get the maximum buffers size for output  */
                obuf = sclp_ioctls.max_sccb << 12;
-               if (put_user(obuf, (unsigned int *) arg))
+               if (put_user(obuf, (unsigned int __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPGKBUF:
                /* get the number of buffers got from kernel at startup */
-               if (put_user(sclp_ioctls.kmem_sccb, (unsigned short *) arg))
+               if (put_user(sclp_ioctls.kmem_sccb, (unsigned short __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPSCASE:
                /* enable/disable conversion from upper to lower case */
-               if (get_user(sclp_ioctls.tolower, (unsigned char *) arg))
+               if (get_user(sclp_ioctls.tolower, (unsigned char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPGCASE:
                /* Is conversion from upper to lower case of input enabled? */
-               if (put_user(sclp_ioctls.tolower, (unsigned char *) arg))
+               if (put_user(sclp_ioctls.tolower, (unsigned char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPSDELIM:
@@ -194,7 +195,7 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file,
                 * set special character used for separating upper and
                 * lower case, 0x00 disables this feature
                 */
-               if (get_user(sclp_ioctls.delim, (unsigned char *) arg))
+               if (get_user(sclp_ioctls.delim, (unsigned char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPGDELIM:
@@ -202,7 +203,7 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file,
                 * get special character used for separating upper and
                 * lower case, 0x00 disables this feature
                 */
-               if (put_user(sclp_ioctls.delim, (unsigned char *) arg))
+               if (put_user(sclp_ioctls.delim, (unsigned char __user *) arg))
                        rc = -EFAULT;
                break;
        case TIOCSCLPSINIT:
@@ -255,32 +256,26 @@ static void
 sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
 {
        unsigned long flags;
-       struct sclp_buffer *next;
        void *page;
 
-       /* Ignore return code - because tty-writes aren't critical,
-          we do without a sophisticated error recovery mechanism.  */
-       page = sclp_unmake_buffer(buffer);
-       spin_lock_irqsave(&sclp_tty_lock, flags);
-       /* Remove buffer from outqueue */
-       list_del(&buffer->list);
-       sclp_tty_buffer_count--;
-       list_add_tail((struct list_head *) page, &sclp_tty_pages);
-       /* Check if there is a pending buffer on the out queue. */
-       next = NULL;
-       if (!list_empty(&sclp_tty_outqueue))
-               next = list_entry(sclp_tty_outqueue.next,
-                                 struct sclp_buffer, list);
-       spin_unlock_irqrestore(&sclp_tty_lock, flags);
-       if (next != NULL)
-               sclp_emit_buffer(next, sclp_ttybuf_callback);
+       do {
+               page = sclp_unmake_buffer(buffer);
+               spin_lock_irqsave(&sclp_tty_lock, flags);
+               /* Remove buffer from outqueue */
+               list_del(&buffer->list);
+               sclp_tty_buffer_count--;
+               list_add_tail((struct list_head *) page, &sclp_tty_pages);
+               /* Check if there is a pending buffer on the out queue. */
+               buffer = NULL;
+               if (!list_empty(&sclp_tty_outqueue))
+                       buffer = list_entry(sclp_tty_outqueue.next,
+                                           struct sclp_buffer, list);
+               spin_unlock_irqrestore(&sclp_tty_lock, flags);
+       } while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
        wake_up(&sclp_tty_waitq);
        /* check if the tty needs a wake up call */
        if (sclp_tty != NULL) {
-               if ((sclp_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   sclp_tty->ldisc.write_wakeup)
-                       (sclp_tty->ldisc.write_wakeup)(sclp_tty);
-               wake_up_interruptible(&sclp_tty->write_wait);
+               tty_wakeup(sclp_tty);
        }
 }
 
@@ -289,14 +284,17 @@ __sclp_ttybuf_emit(struct sclp_buffer *buffer)
 {
        unsigned long flags;
        int count;
+       int rc;
 
        spin_lock_irqsave(&sclp_tty_lock, flags);
        list_add_tail(&buffer->list, &sclp_tty_outqueue);
        count = sclp_tty_buffer_count++;
        spin_unlock_irqrestore(&sclp_tty_lock, flags);
-
-       if (count == 0)
-               sclp_emit_buffer(buffer, sclp_ttybuf_callback);
+       if (count)
+               return;
+       rc = sclp_emit_buffer(buffer, sclp_ttybuf_callback);
+       if (rc)
+               sclp_ttybuf_callback(buffer, rc);
 }
 
 /*
@@ -398,35 +396,14 @@ sclp_tty_write_string(const unsigned char *str, int count)
  * routine will return the number of characters actually accepted for writing.
  */
 static int
-sclp_tty_write(struct tty_struct *tty, int from_user,
-              const unsigned char *buf, int count)
+sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-       int length, ret;
-
        if (sclp_tty_chars_count > 0) {
                sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
                sclp_tty_chars_count = 0;
        }
-       if (!from_user) {
-               sclp_tty_write_string(buf, count);
-               return count;
-       }
-       ret = 0;
-       while (count > 0) {
-               length = count < SCLP_TTY_BUF_SIZE ?
-                       count : SCLP_TTY_BUF_SIZE;
-               length -= copy_from_user(sclp_tty_chars, buf, length);
-               if (length == 0) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       break;
-               }
-               sclp_tty_write_string(sclp_tty_chars, length);
-               buf += length;
-               count -= length;
-               ret += length;
-       }
-       return ret;
+       sclp_tty_write_string(buf, count);
+       return count;
 }
 
 /*
@@ -520,25 +497,19 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
        case CTRLCHAR_SYSRQ:
                break;
        case CTRLCHAR_CTRL:
-               sclp_tty->flip.count++;
-               *sclp_tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-               *sclp_tty->flip.char_buf_ptr++ = cchar;
+               tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
                tty_flip_buffer_push(sclp_tty);
                break;
        case CTRLCHAR_NONE:
                /* send (normal) input to line discipline */
-               memcpy(sclp_tty->flip.char_buf_ptr, buf, count);
                if (count < 2 ||
-                   (strncmp ((const char *) buf + count - 2, "^n", 2) &&
-                    strncmp ((const char *) buf + count - 2, "\0252n", 2))) {
-                       sclp_tty->flip.char_buf_ptr[count] = '\n';
-                       count++;
+                   (strncmp((const char *) buf + count - 2, "^n", 2) &&
+                    strncmp((const char *) buf + count - 2, "\252n", 2))) {
+                       /* add the auto \n */
+                       tty_insert_flip_string(sclp_tty, buf, count);
+                       tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
                } else
-                       count -= 2;
-               memset(sclp_tty->flip.flag_buf_ptr, TTY_NORMAL, count);
-               sclp_tty->flip.char_buf_ptr += count;
-               sclp_tty->flip.flag_buf_ptr += count;
-               sclp_tty->flip.count += count;
+                       tty_insert_flip_string(sclp_tty, buf, count - 2);
                tty_flip_buffer_push(sclp_tty);
                break;
        }
@@ -625,7 +596,7 @@ sclp_get_input(unsigned char *start, unsigned char *end)
 
        /* if set in ioctl write operators input to console  */
        if (sclp_ioctls.echo)
-               sclp_tty_write(sclp_tty, 0, start, count);
+               sclp_tty_write(sclp_tty, start, count);
 
        /* transfer input to high level driver */
        sclp_tty_input(start, count);