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