Commit b2b9268a authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: console driver.

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

- 3215: Adapt to notify api change in cio.
- 3215/sclp: move copy_from_user out of locked code.
parent 53e7ea7f
......@@ -96,6 +96,7 @@ struct raw3215_info {
int msg_dstat; /* dstat for pending message */
int msg_cstat; /* cstat for pending message */
int line_pos; /* position on the line (for tabs) */
char ubuffer[80]; /* copy_from_user buffer */
};
/* array of 3215 devices structures */
......@@ -532,15 +533,12 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length)
/*
* String write routine for 3215 devices
*/
static int
raw3215_write(struct raw3215_info *raw, const char *str,
int from_user, unsigned int length)
static void
raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length)
{
unsigned long flags;
int ret, c;
int count;
int c, count;
ret = 0;
while (length > 0) {
spin_lock_irqsave(raw->lock, flags);
count = (length > RAW3215_BUFFER_SIZE) ?
......@@ -550,46 +548,19 @@ raw3215_write(struct raw3215_info *raw, const char *str,
raw3215_make_room(raw, count);
/* copy string to output buffer and convert it to EBCDIC */
if (from_user) {
while (1) {
c = min_t(int, count,
min(RAW3215_BUFFER_SIZE - raw->count,
RAW3215_BUFFER_SIZE - raw->head));
if (c <= 0)
break;
c -= copy_from_user(raw->buffer + raw->head,
str, c);
if (c == 0) {
if (!ret)
ret = -EFAULT;
break;
}
ASCEBC(raw->buffer + raw->head, c);
raw->head = (raw->head + c) &
(RAW3215_BUFFER_SIZE - 1);
raw->count += c;
raw->line_pos += c;
str += c;
count -= c;
ret += c;
}
} else {
while (1) {
c = min_t(int, count,
min(RAW3215_BUFFER_SIZE - raw->count,
RAW3215_BUFFER_SIZE - raw->head));
if (c <= 0)
break;
memcpy(raw->buffer + raw->head, str, c);
ASCEBC(raw->buffer + raw->head, c);
raw->head = (raw->head + c) &
(RAW3215_BUFFER_SIZE - 1);
raw->count += c;
raw->line_pos += c;
str += c;
count -= c;
ret += c;
}
while (1) {
c = min_t(int, count,
min(RAW3215_BUFFER_SIZE - raw->count,
RAW3215_BUFFER_SIZE - raw->head));
if (c <= 0)
break;
memcpy(raw->buffer + raw->head, str, c);
ASCEBC(raw->buffer + raw->head, c);
raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1);
raw->count += c;
raw->line_pos += c;
str += c;
count -= c;
}
if (!(raw->flags & RAW3215_WORKING)) {
raw3215_mk_write_req(raw);
......@@ -598,8 +569,6 @@ raw3215_write(struct raw3215_info *raw, const char *str,
}
spin_unlock_irqrestore(raw->lock, flags);
}
return ret;
}
/*
......@@ -752,11 +721,12 @@ raw3215_probe (struct ccw_device *cdev)
return 0;
}
static int
static void
raw3215_remove (struct ccw_device *cdev)
{
struct raw3215_info *raw;
ccw_device_set_offline(cdev);
raw = cdev->dev.driver_data;
if (raw) {
cdev->dev.driver_data = NULL;
......@@ -764,7 +734,6 @@ raw3215_remove (struct ccw_device *cdev)
kfree(raw->buffer);
kfree(raw);
}
return 0;
}
static int
......@@ -825,7 +794,7 @@ con3215_write(struct console *co, const char *str, unsigned int count)
for (i = 0; i < count; i++)
if (str[i] == '\t' || str[i] == '\n')
break;
raw3215_write(raw, str, 0, i);
raw3215_write(raw, str, i);
count -= i;
str += i;
if (count > 0) {
......@@ -1021,12 +990,29 @@ tty3215_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
struct raw3215_info *raw;
int ret = 0;
int length, ret;
if (!tty)
return 0;
raw = (struct raw3215_info *) tty->driver_data;
ret = raw3215_write(raw, buf, from_user, count);
if (!from_user) {
raw3215_write(raw, buf, count);
return count;
}
ret = 0;
while (count > 0) {
length = count < 80 ? count : 80;
length -= copy_from_user(raw->ubuffer, buf, length);
if (length == 0) {
if (!ret)
ret = -EFAULT;
break;
}
raw3215_write(raw, raw->ubuffer, count);
buf += length;
count -= length;
ret += length;
}
return ret;
}
......
......@@ -134,8 +134,8 @@ sclp_console_write(struct console *console, const char *message,
}
/* try to write the string to the current output buffer */
written = sclp_write(sclp_conbuf, (const unsigned char *)
message, count, 0);
if (written == -EFAULT || written == count)
message, count);
if (written == count)
break;
/*
* Not all characters could be written to the current
......
......@@ -175,11 +175,9 @@ sclp_finalize_mto(struct sclp_buffer *buffer)
* is not busy)
*/
int
sclp_write(struct sclp_buffer *buffer,
const unsigned char *msg, int count, int from_user)
sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
{
int spaces, i_msg;
char ch;
int rc;
/*
......@@ -206,13 +204,7 @@ sclp_write(struct sclp_buffer *buffer,
* This is in order to a slim and quick implementation.
*/
for (i_msg = 0; i_msg < count; i_msg++) {
if (from_user) {
if (get_user(ch, msg + i_msg) != 0)
return -EFAULT;
} else
ch = msg[i_msg];
switch (ch) {
switch (msg[i_msg]) {
case '\n': /* new line, line feed (ASCII) */
/* check if new mto needs to be created */
if (buffer->current_line == NULL) {
......@@ -286,7 +278,7 @@ sclp_write(struct sclp_buffer *buffer,
break;
default: /* no escape character */
/* do not output unprintable characters */
if (!isprint(ch))
if (!isprint(msg[i_msg]))
break;
/* check if new mto needs to be created */
if (buffer->current_line == NULL) {
......@@ -295,7 +287,7 @@ sclp_write(struct sclp_buffer *buffer,
if (rc)
return i_msg;
}
*buffer->current_line++ = sclp_ascebc(ch);
*buffer->current_line++ = sclp_ascebc(msg[i_msg]);
buffer->current_length++;
break;
}
......
......@@ -89,7 +89,7 @@ int sclp_rw_init(void);
struct sclp_buffer *sclp_make_buffer(void *, unsigned short, unsigned short);
void *sclp_unmake_buffer(struct sclp_buffer *);
int sclp_buffer_space(struct sclp_buffer *);
int sclp_write(struct sclp_buffer *buffer, const unsigned char *, int, int);
int sclp_write(struct sclp_buffer *buffer, const unsigned char *, int);
void sclp_emit_buffer(struct sclp_buffer *,void (*)(struct sclp_buffer *,int));
void sclp_set_columns(struct sclp_buffer *, unsigned short);
void sclp_set_htab(struct sclp_buffer *, unsigned short);
......
......@@ -322,7 +322,7 @@ sclp_tty_timeout(unsigned long data)
* Write a string to the sclp tty.
*/
static void
sclp_tty_write_string(const unsigned char *str, int count, int from_user)
sclp_tty_write_string(const unsigned char *str, int count)
{
unsigned long flags;
void *page;
......@@ -348,8 +348,8 @@ sclp_tty_write_string(const unsigned char *str, int count, int from_user)
sclp_ioctls.htab);
}
/* try to write the string to the current output buffer */
written = sclp_write(sclp_ttybuf, str, count, from_user);
if (written == -EFAULT || written == count)
written = sclp_write(sclp_ttybuf, str, count);
if (written == count)
break;
/*
* Not all characters could be written to the current
......@@ -389,12 +389,32 @@ static int
sclp_tty_write(struct tty_struct *tty, int from_user,
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, 0);
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
sclp_tty_chars_count = 0;
}
sclp_tty_write_string(buf, count, from_user);
return count;
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;
}
/*
......@@ -412,7 +432,7 @@ sclp_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
sclp_tty_chars[sclp_tty_chars_count++] = ch;
if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) {
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
sclp_tty_chars_count = 0;
}
}
......@@ -425,7 +445,7 @@ static void
sclp_tty_flush_chars(struct tty_struct *tty)
{
if (sclp_tty_chars_count > 0) {
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
sclp_tty_chars_count = 0;
}
}
......@@ -464,7 +484,7 @@ static void
sclp_tty_flush_buffer(struct tty_struct *tty)
{
if (sclp_tty_chars_count > 0) {
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
sclp_tty_chars_count = 0;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment