/* 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)) {
+ (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++;
} else
{
struct gds_vector *vec;
- for (vec = start; vec < end; (void *) vec += vec->length)
+ for (vec = start; vec < end; vec = (void *) vec + vec->length)
if (vec->gds_id == id)
return vec;
return NULL;
{
struct gds_subvector *subvec;
- for (subvec = start; subvec < end; (void *) subvec += subvec->length)
+ for (subvec = start; subvec < end;
+ subvec = (void *) subvec + subvec->length)
if (subvec->key == key)
return subvec;
return NULL;
break;
sclp_get_input((unsigned char *)(subvec + 1),
(unsigned char *) subvec + subvec->length);
- (void *) subvec += subvec->length;
+ subvec = (void *) subvec + subvec->length;
}
}
break;
sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1),
(void *)subvec + subvec->length);
- (void *) subvec += subvec->length;
+ subvec = (void *) subvec + subvec->length;
}
}
break;
sclp_eval_textcmd((struct gds_subvector *)(vec + 1),
(void *) vec + vec->length);
- (void *) vec += vec->length;
+ vec = (void *) vec + vec->length;
}
}
#define SCLP_VT220_MAJOR TTY_MAJOR
#define SCLP_VT220_MINOR 65
#define SCLP_VT220_DRIVER_NAME "sclp_vt220"
-#define SCLP_VT220_DEVICE_NAME "sclp_vt"
+#define SCLP_VT220_DEVICE_NAME "ttysclp"
#define SCLP_VT220_CONSOLE_NAME "ttyS"
#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
+#define SCLP_VT220_BUF_SIZE 80
/* Representation of a single write request */
struct sclp_vt220_request {
/*
* Add msg to buffer associated with request. Return the number of characters
- * added or -EFAULT on error.
+ * added.
*/
static int
sclp_vt220_add_msg(struct sclp_vt220_request *request,
- const unsigned char *msg, int count, int from_user,
- int convertlf)
+ const unsigned char *msg, int count, int convertlf)
{
struct sclp_vt220_sccb *sccb;
void *buffer;
(from < count) && (to < sclp_vt220_space_left(request));
from++) {
/* Retrieve character */
- if (from_user) {
- if (get_user(c, msg + from) != 0)
- return -EFAULT;
- } else
- c = msg[from];
+ c = msg[from];
/* Perform conversion */
if (c == 0x0a) {
if (to + 1 < sclp_vt220_space_left(request)) {
sccb->evbuf.length += to;
return from;
} else {
- if (from_user) {
- if (copy_from_user(buffer, (void *) msg, count) != 0)
- return -EFAULT;
- }
- else
- memcpy(buffer, (const void *) msg, count);
+ memcpy(buffer, (const void *) msg, count);
sccb->header.length += count;
sccb->evbuf.length += count;
return count;
/*
* Internal implementation of the write function. Write COUNT bytes of data
- * from memory at BUF which may reside in user space (specified by FROM_USER)
+ * from memory at BUF
* to the SCLP interface. In case that the data does not fit into the current
* write buffer, emit the current one and allocate a new one. If there are no
* more empty buffers available, wait until one gets emptied. If DO_SCHEDULE
* of bytes written.
*/
static int
-__sclp_vt220_write(int from_user, const unsigned char *buf, int count,
- int do_schedule, int convertlf)
+__sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
+ int convertlf)
{
unsigned long flags;
void *page;
}
/* Try to write the string to the current request buffer */
written = sclp_vt220_add_msg(sclp_vt220_current_request,
- buf, count, from_user, convertlf);
- if (written > 0)
- overall_written += written;
- if (written == -EFAULT || written == count)
+ buf, count, convertlf);
+ overall_written += written;
+ if (written == count)
break;
/*
* Not all characters could be written to the current
sclp_vt220_write(struct tty_struct *tty, int from_user,
const unsigned char *buf, int count)
{
- return __sclp_vt220_write(from_user, buf, count, 1, 0);
+ int length;
+ int ret;
+
+ if (!from_user)
+ return __sclp_vt220_write(buf, count, 1, 0);
+ /* Use intermediate buffer to prevent calling copy_from_user() while
+ * holding a lock. */
+ ret = 0;
+ while (count > 0) {
+ length = count < SCLP_VT220_BUF_SIZE ?
+ count : SCLP_VT220_BUF_SIZE;
+ length -= copy_from_user(tty->driver_data, buf, length);
+ if (length == 0) {
+ if (!ret)
+ return -EFAULT;
+ break;
+ }
+ length = __sclp_vt220_write(tty->driver_data, length, 1, 0);
+ buf += length;
+ count -= length;
+ ret += length;
+ }
+ return ret;
}
#define SCLP_VT220_SESSION_ENDED 0x01
static int
sclp_vt220_open(struct tty_struct *tty, struct file *filp)
{
- sclp_vt220_tty = tty;
- tty->driver_data = NULL;
- tty->low_latency = 0;
+ if (tty->count == 1) {
+ sclp_vt220_tty = tty;
+ tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
+ if (tty->driver_data == NULL)
+ return -ENOMEM;
+ tty->low_latency = 0;
+ }
return 0;
}
static void
sclp_vt220_close(struct tty_struct *tty, struct file *filp)
{
- if (tty->count > 1)
- return;
- sclp_vt220_tty = NULL;
+ if (tty->count == 1) {
+ sclp_vt220_tty = NULL;
+ kfree(tty->driver_data);
+ tty->driver_data = NULL;
+ }
}
/*
static void
sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
{
- __sclp_vt220_write(0, &ch, 1, 0, 0);
+ __sclp_vt220_write(&ch, 1, 0, 0);
}
/*
static void
sclp_vt220_con_write(struct console *con, const char *buf, unsigned int count)
{
- __sclp_vt220_write(0, (const unsigned char *) buf, count, 1, 1);
+ __sclp_vt220_write((const unsigned char *) buf, count, 1, 1);
}
static struct tty_driver *