#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>
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:
* 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
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:
* 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:
* 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:
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);
}
}
{
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);
}
/*
* 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;
}
/*
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;
}
/* 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);