summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/n_tty.c752
-rw-r--r--drivers/tty/pty.c30
-rw-r--r--drivers/tty/serial/8250/8250.c9
-rw-r--r--drivers/tty/serial/8250/8250.h36
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/samsung.c16
-rw-r--r--drivers/tty/tty_audit.c15
-rw-r--r--drivers/tty/tty_buffer.c228
-rw-r--r--drivers/tty/tty_io.c15
-rw-r--r--drivers/tty/tty_ldisc.c15
-rw-r--r--drivers/tty/tty_port.c2
-rw-r--r--drivers/tty/vt/selection.c9
12 files changed, 627 insertions, 502 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 8c0b7b4..60b076c 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -73,10 +73,42 @@
#define ECHO_OP_SET_CANON_COL 0x81
#define ECHO_OP_ERASE_TAB 0x82
+struct n_tty_data {
+ unsigned int column;
+ unsigned long overrun_time;
+ int num_overrun;
+
+ unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+ unsigned char echo_overrun:1;
+
+ DECLARE_BITMAP(process_char_map, 256);
+ DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
+
+ char *read_buf;
+ int read_head;
+ int read_tail;
+ int read_cnt;
+
+ unsigned char *echo_buf;
+ unsigned int echo_pos;
+ unsigned int echo_cnt;
+
+ int canon_data;
+ unsigned long canon_head;
+ unsigned int canon_column;
+
+ struct mutex atomic_read_lock;
+ struct mutex output_lock;
+ struct mutex echo_lock;
+ spinlock_t read_lock;
+};
+
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
unsigned char __user *ptr)
{
- tty_audit_add_data(tty, &x, 1);
+ struct n_tty_data *ldata = tty->disc_data;
+
+ tty_audit_add_data(tty, &x, 1, ldata->icanon);
return put_user(x, ptr);
}
@@ -92,17 +124,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
static void n_tty_set_room(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
int left;
int old_left;
- /* tty->read_cnt is not read locked ? */
+ /* ldata->read_cnt is not read locked ? */
if (I_PARMRK(tty)) {
/* Multiply read_cnt by 3, since each byte might take up to
* three times as many spaces when PARMRK is set (depending on
* its flags, e.g. parity error). */
- left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
+ left = N_TTY_BUF_SIZE - ldata->read_cnt * 3 - 1;
} else
- left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+ left = N_TTY_BUF_SIZE - ldata->read_cnt - 1;
/*
* If we are doing input canonicalization, and there are no
@@ -111,44 +144,47 @@ static void n_tty_set_room(struct tty_struct *tty)
* characters will be beeped.
*/
if (left <= 0)
- left = tty->icanon && !tty->canon_data;
+ left = ldata->icanon && !ldata->canon_data;
old_left = tty->receive_room;
tty->receive_room = left;
/* Did this open up the receive buffer? We may need to flip */
- if (left && !old_left)
- schedule_work(&tty->buf.work);
+ if (left && !old_left) {
+ WARN_RATELIMIT(tty->port->itty == NULL,
+ "scheduling with invalid itty");
+ schedule_work(&tty->port->buf.work);
+ }
}
-static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
+static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata)
{
- if (tty->read_cnt < N_TTY_BUF_SIZE) {
- tty->read_buf[tty->read_head] = c;
- tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt++;
+ if (ldata->read_cnt < N_TTY_BUF_SIZE) {
+ ldata->read_buf[ldata->read_head] = c;
+ ldata->read_head = (ldata->read_head + 1) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt++;
}
}
/**
* put_tty_queue - add character to tty
* @c: character
- * @tty: tty device
+ * @ldata: n_tty data
*
* Add a character to the tty read_buf queue. This is done under the
* read_lock to serialize character addition and also to protect us
* against parallel reads or flushes
*/
-static void put_tty_queue(unsigned char c, struct tty_struct *tty)
+static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
{
unsigned long flags;
/*
* The problem of stomping on the buffers ends here.
* Why didn't anyone see this one coming? --AJK
*/
- spin_lock_irqsave(&tty->read_lock, flags);
- put_tty_queue_nolock(c, tty);
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ put_tty_queue_nolock(c, ldata);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
}
/**
@@ -179,18 +215,19 @@ static void check_unthrottle(struct tty_struct *tty)
static void reset_buffer_flags(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned long flags;
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_head = tty->read_tail = tty->read_cnt = 0;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_head = ldata->read_tail = ldata->read_cnt = 0;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
- mutex_lock(&tty->echo_lock);
- tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
- mutex_unlock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
+ ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0;
+ mutex_unlock(&ldata->echo_lock);
- tty->canon_head = tty->canon_data = tty->erasing = 0;
- memset(&tty->read_flags, 0, sizeof tty->read_flags);
+ ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
+ bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
n_tty_set_room(tty);
}
@@ -235,18 +272,19 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned long flags;
ssize_t n = 0;
- spin_lock_irqsave(&tty->read_lock, flags);
- if (!tty->icanon) {
- n = tty->read_cnt;
- } else if (tty->canon_data) {
- n = (tty->canon_head > tty->read_tail) ?
- tty->canon_head - tty->read_tail :
- tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ if (!ldata->icanon) {
+ n = ldata->read_cnt;
+ } else if (ldata->canon_data) {
+ n = (ldata->canon_head > ldata->read_tail) ?
+ ldata->canon_head - ldata->read_tail :
+ ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail);
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
return n;
}
@@ -301,6 +339,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty)
static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
{
+ struct n_tty_data *ldata = tty->disc_data;
int spaces;
if (!space)
@@ -309,48 +348,48 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
switch (c) {
case '\n':
if (O_ONLRET(tty))
- tty->column = 0;
+ ldata->column = 0;
if (O_ONLCR(tty)) {
if (space < 2)
return -1;
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
tty->ops->write(tty, "\r\n", 2);
return 2;
}
- tty->canon_column = tty->column;
+ ldata->canon_column = ldata->column;
break;
case '\r':
- if (O_ONOCR(tty) && tty->column == 0)
+ if (O_ONOCR(tty) && ldata->column == 0)
return 0;
if (O_OCRNL(tty)) {
c = '\n';
if (O_ONLRET(tty))
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
break;
}
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
break;
case '\t':
- spaces = 8 - (tty->column & 7);
+ spaces = 8 - (ldata->column & 7);
if (O_TABDLY(tty) == XTABS) {
if (space < spaces)
return -1;
- tty->column += spaces;
+ ldata->column += spaces;
tty->ops->write(tty, " ", spaces);
return spaces;
}
- tty->column += spaces;
+ ldata->column += spaces;
break;
case '\b':
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
break;
default:
if (!iscntrl(c)) {
if (O_OLCUC(tty))
c = toupper(c);
if (!is_continuation(c, tty))
- tty->column++;
+ ldata->column++;
}
break;
}
@@ -375,14 +414,15 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
static int process_output(unsigned char c, struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
int space, retval;
- mutex_lock(&tty->output_lock);
+ mutex_lock(&ldata->output_lock);
space = tty_write_room(tty);
retval = do_output_char(c, tty, space);
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->output_lock);
if (retval < 0)
return -1;
else
@@ -411,15 +451,16 @@ static int process_output(unsigned char c, struct tty_struct *tty)
static ssize_t process_output_block(struct tty_struct *tty,
const unsigned char *buf, unsigned int nr)
{
+ struct n_tty_data *ldata = tty->disc_data;
int space;
int i;
const unsigned char *cp;
- mutex_lock(&tty->output_lock);
+ mutex_lock(&ldata->output_lock);
space = tty_write_room(tty);
if (!space) {
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->output_lock);
return 0;
}
if (nr > space)
@@ -431,30 +472,30 @@ static ssize_t process_output_block(struct tty_struct *tty,
switch (c) {
case '\n':
if (O_ONLRET(tty))
- tty->column = 0;
+ ldata->column = 0;
if (O_ONLCR(tty))
goto break_out;
- tty->canon_column = tty->column;
+ ldata->canon_column = ldata->column;
break;
case '\r':
- if (O_ONOCR(tty) && tty->column == 0)
+ if (O_ONOCR(tty) && ldata->column == 0)
goto break_out;
if (O_OCRNL(tty))
goto break_out;
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
break;
case '\t':
goto break_out;
case '\b':
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
break;
default:
if (!iscntrl(c)) {
if (O_OLCUC(tty))
goto break_out;
if (!is_continuation(c, tty))
- tty->column++;
+ ldata->column++;
}
break;
}
@@ -462,7 +503,7 @@ static ssize_t process_output_block(struct tty_struct *tty,
break_out:
i = tty->ops->write(tty, buf, i);
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->output_lock);
return i;
}
@@ -494,21 +535,22 @@ break_out:
static void process_echoes(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
int space, nr;
unsigned char c;
unsigned char *cp, *buf_end;
- if (!tty->echo_cnt)
+ if (!ldata->echo_cnt)
return;
- mutex_lock(&tty->output_lock);
- mutex_lock(&tty->echo_lock);
+ mutex_lock(&ldata->output_lock);
+ mutex_lock(&ldata->echo_lock);
space = tty_write_room(tty);
- buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
- cp = tty->echo_buf + tty->echo_pos;
- nr = tty->echo_cnt;
+ buf_end = ldata->echo_buf + N_TTY_BUF_SIZE;
+ cp = ldata->echo_buf + ldata->echo_pos;
+ nr = ldata->echo_cnt;
while (nr > 0) {
c = *cp;
if (c == ECHO_OP_START) {
@@ -545,7 +587,7 @@ static void process_echoes(struct tty_struct *tty)
* Otherwise, tab spacing is normal.
*/
if (!(num_chars & 0x80))
- num_chars += tty->canon_column;
+ num_chars += ldata->canon_column;
num_bs = 8 - (num_chars & 7);
if (num_bs > space) {
@@ -555,22 +597,22 @@ static void process_echoes(struct tty_struct *tty)
space -= num_bs;
while (num_bs--) {
tty_put_char(tty, '\b');
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
}
cp += 3;
nr -= 3;
break;
case ECHO_OP_SET_CANON_COL:
- tty->canon_column = tty->column;
+ ldata->canon_column = ldata->column;
cp += 2;
nr -= 2;
break;
case ECHO_OP_MOVE_BACK_COL:
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
cp += 2;
nr -= 2;
break;
@@ -582,7 +624,7 @@ static void process_echoes(struct tty_struct *tty)
break;
}
tty_put_char(tty, ECHO_OP_START);
- tty->column++;
+ ldata->column++;
space--;
cp += 2;
nr -= 2;
@@ -604,7 +646,7 @@ static void process_echoes(struct tty_struct *tty)
}
tty_put_char(tty, '^');
tty_put_char(tty, op ^ 0100);
- tty->column += 2;
+ ldata->column += 2;
space -= 2;
cp += 2;
nr -= 2;
@@ -635,20 +677,20 @@ static void process_echoes(struct tty_struct *tty)
}
if (nr == 0) {
- tty->echo_pos = 0;
- tty->echo_cnt = 0;
- tty->echo_overrun = 0;
+ ldata->echo_pos = 0;
+ ldata->echo_cnt = 0;
+ ldata->echo_overrun = 0;
} else {
- int num_processed = tty->echo_cnt - nr;
- tty->echo_pos += num_processed;
- tty->echo_pos &= N_TTY_BUF_SIZE - 1;
- tty->echo_cnt = nr;
+ int num_processed = ldata->echo_cnt - nr;
+ ldata->echo_pos += num_processed;
+ ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
+ ldata->echo_cnt = nr;
if (num_processed > 0)
- tty->echo_overrun = 0;
+ ldata->echo_overrun = 0;
}
- mutex_unlock(&tty->echo_lock);
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->echo_lock);
+ mutex_unlock(&ldata->output_lock);
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
@@ -657,72 +699,70 @@ static void process_echoes(struct tty_struct *tty)
/**
* add_echo_byte - add a byte to the echo buffer
* @c: unicode byte to echo
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add a character or operation byte to the echo buffer.
*
* Should be called under the echo lock to protect the echo buffer.
*/
-static void add_echo_byte(unsigned char c, struct tty_struct *tty)
+static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
{
int new_byte_pos;
- if (tty->echo_cnt == N_TTY_BUF_SIZE) {
+ if (ldata->echo_cnt == N_TTY_BUF_SIZE) {
/* Circular buffer is already at capacity */
- new_byte_pos = tty->echo_pos;
+ new_byte_pos = ldata->echo_pos;
/*
* Since the buffer start position needs to be advanced,
* be sure to step by a whole operation byte group.
*/
- if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
- if (tty->echo_buf[(tty->echo_pos + 1) &
+ if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) {
+ if (ldata->echo_buf[(ldata->echo_pos + 1) &
(N_TTY_BUF_SIZE - 1)] ==
ECHO_OP_ERASE_TAB) {
- tty->echo_pos += 3;
- tty->echo_cnt -= 2;
+ ldata->echo_pos += 3;
+ ldata->echo_cnt -= 2;
} else {
- tty->echo_pos += 2;
- tty->echo_cnt -= 1;
+ ldata->echo_pos += 2;
+ ldata->echo_cnt -= 1;
}
} else {
- tty->echo_pos++;
+ ldata->echo_pos++;
}
- tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+ ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
- tty->echo_overrun = 1;
+ ldata->echo_overrun = 1;
} else {
- new_byte_pos = tty->echo_pos + tty->echo_cnt;
+ new_byte_pos = ldata->echo_pos + ldata->echo_cnt;
new_byte_pos &= N_TTY_BUF_SIZE - 1;
- tty->echo_cnt++;
+ ldata->echo_cnt++;
}
- tty->echo_buf[new_byte_pos] = c;
+ ldata->echo_buf[new_byte_pos] = c;
}
/**
* echo_move_back_col - add operation to move back a column
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add an operation to the echo buffer to move back one column.
*
* Locking: echo_lock to protect the echo buffer
*/
-static void echo_move_back_col(struct tty_struct *tty)
+static void echo_move_back_col(struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
-
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
-
- mutex_unlock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
+ mutex_unlock(&ldata->echo_lock);
}
/**
* echo_set_canon_col - add operation to set the canon column
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add an operation to the echo buffer to set the canon column
* to the current column.
@@ -730,21 +770,19 @@ static void echo_move_back_col(struct tty_struct *tty)
* Locking: echo_lock to protect the echo buffer
*/
-static void echo_set_canon_col(struct tty_struct *tty)
+static void echo_set_canon_col(struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
-
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
-
- mutex_unlock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
+ mutex_unlock(&ldata->echo_lock);
}
/**
* echo_erase_tab - add operation to erase a tab
* @num_chars: number of character columns already used
* @after_tab: true if num_chars starts after a previous tab
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add an operation to the echo buffer to erase a tab.
*
@@ -758,12 +796,12 @@ static void echo_set_canon_col(struct tty_struct *tty)
*/
static void echo_erase_tab(unsigned int num_chars, int after_tab,
- struct tty_struct *tty)
+ struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_ERASE_TAB, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
/* We only need to know this modulo 8 (tab spacing) */
num_chars &= 7;
@@ -772,9 +810,9 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,
if (after_tab)
num_chars |= 0x80;
- add_echo_byte(num_chars, tty);
+ add_echo_byte(num_chars, ldata);
- mutex_unlock(&tty->echo_lock);
+ mutex_unlock(&ldata->echo_lock);
}
/**
@@ -790,18 +828,16 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,
* Locking: echo_lock to protect the echo buffer
*/
-static void echo_char_raw(unsigned char c, struct tty_struct *tty)
+static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
-
+ mutex_lock(&ldata->echo_lock);
if (c == ECHO_OP_START) {
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_START, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_START, ldata);
} else {
- add_echo_byte(c, tty);
+ add_echo_byte(c, ldata);
}
-
- mutex_unlock(&tty->echo_lock);
+ mutex_unlock(&ldata->echo_lock);
}
/**
@@ -820,30 +856,32 @@ static void echo_char_raw(unsigned char c, struct tty_struct *tty)
static void echo_char(unsigned char c, struct tty_struct *tty)
{
- mutex_lock(&tty->echo_lock);
+ struct n_tty_data *ldata = tty->disc_data;
+
+ mutex_lock(&ldata->echo_lock);
if (c == ECHO_OP_START) {
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_START, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_START, ldata);
} else {
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(c, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(c, ldata);
}
- mutex_unlock(&tty->echo_lock);
+ mutex_unlock(&ldata->echo_lock);
}
/**
* finish_erasing - complete erase
- * @tty: tty doing the erase
+ * @ldata: n_tty data
*/
-static inline void finish_erasing(struct tty_struct *tty)
+static inline void finish_erasing(struct n_tty_data *ldata)
{
- if (tty->erasing) {
- echo_char_raw('/', tty);
- tty->erasing = 0;
+ if (ldata->erasing) {
+ echo_char_raw('/', ldata);
+ ldata->erasing = 0;
}
}
@@ -861,12 +899,13 @@ static inline void finish_erasing(struct tty_struct *tty)
static void eraser(unsigned char c, struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
enum { ERASE, WERASE, KILL } kill_type;
int head, seen_alnums, cnt;
unsigned long flags;
/* FIXME: locking needed ? */
- if (tty->read_head == tty->canon_head) {
+ if (ldata->read_head == ldata->canon_head) {
/* process_output('\a', tty); */ /* what do you think? */
return;
}
@@ -876,24 +915,24 @@ static void eraser(unsigned char c, struct tty_struct *tty)
kill_type = WERASE;
else {
if (!L_ECHO(tty)) {
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
(N_TTY_BUF_SIZE - 1));
- tty->read_head = tty->canon_head;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ ldata->read_head = ldata->canon_head;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
return;
}
if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
(N_TTY_BUF_SIZE - 1));
- tty->read_head = tty->canon_head;
- spin_unlock_irqrestore(&tty->read_lock, flags);
- finish_erasing(tty);
+ ldata->read_head = ldata->canon_head;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
+ finish_erasing(ldata);
echo_char(KILL_CHAR(tty), tty);
/* Add a newline if ECHOK is on and ECHOKE is off. */
if (L_ECHOK(tty))
- echo_char_raw('\n', tty);
+ echo_char_raw('\n', ldata);
return;
}
kill_type = KILL;
@@ -901,14 +940,14 @@ static void eraser(unsigned char c, struct tty_struct *tty)
seen_alnums = 0;
/* FIXME: Locking ?? */
- while (tty->read_head != tty->canon_head) {
- head = tty->read_head;
+ while (ldata->read_head != ldata->canon_head) {
+ head = ldata->read_head;
/* erase a single possibly multibyte character */
do {
head = (head - 1) & (N_TTY_BUF_SIZE-1);
- c = tty->read_buf[head];
- } while (is_continuation(c, tty) && head != tty->canon_head);
+ c = ldata->read_buf[head];
+ } while (is_continuation(c, tty) && head != ldata->canon_head);
/* do not partially erase */
if (is_continuation(c, tty))
@@ -921,30 +960,31 @@ static void eraser(unsigned char c, struct tty_struct *tty)
else if (seen_alnums)
break;
}
- cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_head = head;
- tty->read_cnt -= cnt;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_head = head;
+ ldata->read_cnt -= cnt;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
- if (!tty->erasing) {
- echo_char_raw('\\', tty);
- tty->erasing = 1;
+ if (!ldata->erasing) {
+ echo_char_raw('\\', ldata);
+ ldata->erasing = 1;
}
/* if cnt > 1, output a multi-byte character */
echo_char(c, tty);
while (--cnt > 0) {
head = (head+1) & (N_TTY_BUF_SIZE-1);
- echo_char_raw(tty->read_buf[head], tty);
- echo_move_back_col(tty);
+ echo_char_raw(ldata->read_buf[head],
+ ldata);
+ echo_move_back_col(ldata);
}
} else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
} else if (c == '\t') {
unsigned int num_chars = 0;
int after_tab = 0;
- unsigned long tail = tty->read_head;
+ unsigned long tail = ldata->read_head;
/*
* Count the columns used for characters
@@ -953,9 +993,9 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* This info is used to go back the correct
* number of columns.
*/
- while (tail != tty->canon_head) {
+ while (tail != ldata->canon_head) {
tail = (tail-1) & (N_TTY_BUF_SIZE-1);
- c = tty->read_buf[tail];
+ c = ldata->read_buf[tail];
if (c == '\t') {
after_tab = 1;
break;
@@ -966,25 +1006,25 @@ static void eraser(unsigned char c, struct tty_struct *tty)
num_chars++;
}
}
- echo_erase_tab(num_chars, after_tab, tty);
+ echo_erase_tab(num_chars, after_tab, ldata);
} else {
if (iscntrl(c) && L_ECHOCTL(tty)) {
- echo_char_raw('\b', tty);
- echo_char_raw(' ', tty);
- echo_char_raw('\b', tty);
+ echo_char_raw('\b', ldata);
+ echo_char_raw(' ', ldata);
+ echo_char_raw('\b', ldata);
}
if (!iscntrl(c) || L_ECHOCTL(tty)) {
- echo_char_raw('\b', tty);
- echo_char_raw(' ', tty);
- echo_char_raw('\b', tty);
+ echo_char_raw('\b', ldata);
+ echo_char_raw(' ', ldata);
+ echo_char_raw('\b', ldata);
}
}
}
if (kill_type == ERASE)
break;
}
- if (tty->read_head == tty->canon_head && L_ECHO(tty))
- finish_erasing(tty);
+ if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
+ finish_erasing(ldata);
}
/**
@@ -1023,6 +1063,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
static inline void n_tty_receive_break(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
if (I_IGNBRK(tty))
return;
if (I_BRKINT(tty)) {
@@ -1030,10 +1072,10 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
return;
}
if (I_PARMRK(tty)) {
- put_tty_queue('\377', tty);
- put_tty_queue('\0', tty);
+ put_tty_queue('\377', ldata);
+ put_tty_queue('\0', ldata);
}
- put_tty_queue('\0', tty);
+ put_tty_queue('\0', ldata);
wake_up_interruptible(&tty->read_wait);
}
@@ -1052,16 +1094,17 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
static inline void n_tty_receive_overrun(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
char buf[64];
- tty->num_overrun++;
- if (time_before(tty->overrun_time, jiffies - HZ) ||
- time_after(tty->overrun_time, jiffies)) {
+ ldata->num_overrun++;
+ if (time_after(jiffies, ldata->overrun_time + HZ) ||
+ time_after(ldata->overrun_time, jiffies)) {
printk(KERN_WARNING "%s: %d input overrun(s)\n",
tty_name(tty, buf),
- tty->num_overrun);
- tty->overrun_time = jiffies;
- tty->num_overrun = 0;
+ ldata->num_overrun);
+ ldata->overrun_time = jiffies;
+ ldata->num_overrun = 0;
}
}
@@ -1076,16 +1119,18 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty)
static inline void n_tty_receive_parity_error(struct tty_struct *tty,
unsigned char c)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
if (I_IGNPAR(tty))
return;
if (I_PARMRK(tty)) {
- put_tty_queue('\377', tty);
- put_tty_queue('\0', tty);
- put_tty_queue(c, tty);
+ put_tty_queue('\377', ldata);
+ put_tty_queue('\0', ldata);
+ put_tty_queue(c, ldata);
} else if (I_INPCK(tty))
- put_tty_queue('\0', tty);
+ put_tty_queue('\0', ldata);
else
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
wake_up_interruptible(&tty->read_wait);
}
@@ -1101,11 +1146,12 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned long flags;
int parmrk;
- if (tty->raw) {
- put_tty_queue(c, tty);
+ if (ldata->raw) {
+ put_tty_queue(c, ldata);
return;
}
@@ -1115,7 +1161,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
c = tolower(c);
if (L_EXTPROC(tty)) {
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
return;
}
@@ -1143,26 +1189,26 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
* handle specially, do shortcut processing to speed things
* up.
*/
- if (!test_bit(c, tty->process_char_map) || tty->lnext) {
- tty->lnext = 0;
+ if (!test_bit(c, ldata->process_char_map) || ldata->lnext) {
+ ldata->lnext = 0;
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
- if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+ if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
/* beep if no space */
if (L_ECHO(tty))
process_output('\a', tty);
return;
}
if (L_ECHO(tty)) {
- finish_erasing(tty);
+ finish_erasing(ldata);
/* Record the column of first canon char. */
- if (tty->canon_head == tty->read_head)
- echo_set_canon_col(tty);
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
echo_char(c, tty);
process_echoes(tty);
}
if (parmrk)
- put_tty_queue(c, tty);
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
+ put_tty_queue(c, ldata);
return;
}
@@ -1218,7 +1264,7 @@ send_signal:
} else if (c == '\n' && I_INLCR(tty))
c = '\r';
- if (tty->icanon) {
+ if (ldata->icanon) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
@@ -1226,12 +1272,12 @@ send_signal:
return;
}
if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
- tty->lnext = 1;
+ ldata->lnext = 1;
if (L_ECHO(tty)) {
- finish_erasing(tty);
+ finish_erasing(ldata);
if (L_ECHOCTL(tty)) {
- echo_char_raw('^', tty);
- echo_char_raw('\b', tty);
+ echo_char_raw('^', ldata);
+ echo_char_raw('\b', ldata);
process_echoes(tty);
}
}
@@ -1239,34 +1285,34 @@ send_signal:
}
if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
L_IEXTEN(tty)) {
- unsigned long tail = tty->canon_head;
+ unsigned long tail = ldata->canon_head;
- finish_erasing(tty);
+ finish_erasing(ldata);
echo_char(c, tty);
- echo_char_raw('\n', tty);
- while (tail != tty->read_head) {
- echo_char(tty->read_buf[tail], tty);
+ echo_char_raw('\n', ldata);
+ while (tail != ldata->read_head) {
+ echo_char(ldata->read_buf[tail], tty);
tail = (tail+1) & (N_TTY_BUF_SIZE-1);
}
process_echoes(tty);
return;
}
if (c == '\n') {
- if (tty->read_cnt >= N_TTY_BUF_SIZE) {
+ if (ldata->read_cnt >= N_TTY_BUF_SIZE) {
if (L_ECHO(tty))
process_output('\a', tty);
return;
}
if (L_ECHO(tty) || L_ECHONL(tty)) {
- echo_char_raw('\n', tty);
+ echo_char_raw('\n', ldata);
process_echoes(tty);
}
goto handle_newline;
}
if (c == EOF_CHAR(tty)) {
- if (tty->read_cnt >= N_TTY_BUF_SIZE)
+ if (ldata->read_cnt >= N_TTY_BUF_SIZE)
return;
- if (tty->canon_head != tty->read_head)
+ if (ldata->canon_head != ldata->read_head)
set_bit(TTY_PUSH, &tty->flags);
c = __DISABLED_CHAR;
goto handle_newline;
@@ -1275,7 +1321,7 @@ send_signal:
(c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
? 1 : 0;
- if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
+ if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
if (L_ECHO(tty))
process_output('\a', tty);
return;
@@ -1285,8 +1331,8 @@ send_signal:
*/
if (L_ECHO(tty)) {
/* Record the column of first canon char. */
- if (tty->canon_head == tty->read_head)
- echo_set_canon_col(tty);
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
echo_char(c, tty);
process_echoes(tty);
}
@@ -1295,15 +1341,15 @@ send_signal:
* EOL_CHAR and EOL2_CHAR?
*/
if (parmrk)
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
handle_newline:
- spin_lock_irqsave(&tty->read_lock, flags);
- set_bit(tty->read_head, tty->read_flags);
- put_tty_queue_nolock(c, tty);
- tty->canon_head = tty->read_head;
- tty->canon_data++;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ set_bit(ldata->read_head, ldata->read_flags);
+ put_tty_queue_nolock(c, ldata);
+ ldata->canon_head = ldata->read_head;
+ ldata->canon_data++;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
@@ -1312,29 +1358,29 @@ handle_newline:
}
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
- if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+ if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
/* beep if no space */
if (L_ECHO(tty))
process_output('\a', tty);
return;
}
if (L_ECHO(tty)) {
- finish_erasing(tty);
+ finish_erasing(ldata);
if (c == '\n')
- echo_char_raw('\n', tty);
+ echo_char_raw('\n', ldata);
else {
/* Record the column of first canon char. */
- if (tty->canon_head == tty->read_head)
- echo_set_canon_col(tty);
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
echo_char(c, tty);
}
process_echoes(tty);
}
if (parmrk)
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
}
@@ -1369,33 +1415,31 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
+ struct n_tty_data *ldata = tty->disc_data;
const unsigned char *p;
char *f, flags = TTY_NORMAL;
int i;
char buf[64];
unsigned long cpuflags;
- if (!tty->read_buf)
- return;
-
- if (tty->real_raw) {
- spin_lock_irqsave(&tty->read_lock, cpuflags);
- i = min(N_TTY_BUF_SIZE - tty->read_cnt,
- N_TTY_BUF_SIZE - tty->read_head);
+ if (ldata->real_raw) {
+ spin_lock_irqsave(&ldata->read_lock, cpuflags);
+ i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
+ N_TTY_BUF_SIZE - ldata->read_head);
i = min(count, i);
- memcpy(tty->read_buf + tty->read_head, cp, i);
- tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt += i;
+ memcpy(ldata->read_buf + ldata->read_head, cp, i);
+ ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt += i;
cp += i;
count -= i;
- i = min(N_TTY_BUF_SIZE - tty->read_cnt,
- N_TTY_BUF_SIZE - tty->read_head);
+ i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
+ N_TTY_BUF_SIZE - ldata->read_head);
i = min(count, i);
- memcpy(tty->read_buf + tty->read_head, cp, i);
- tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt += i;
- spin_unlock_irqrestore(&tty->read_lock, cpuflags);
+ memcpy(ldata->read_buf + ldata->read_head, cp, i);
+ ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt += i;
+ spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
} else {
for (i = count, p = cp, f = fp; i; i--, p++) {
if (f)
@@ -1426,7 +1470,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
n_tty_set_room(tty);
- if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
+ if ((!ldata->icanon && (ldata->read_cnt >= tty->minimum_to_wake)) ||
L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
@@ -1470,25 +1514,25 @@ int is_ignored(int sig)
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
+ struct n_tty_data *ldata = tty->disc_data;
int canon_change = 1;
- BUG_ON(!tty);
if (old)
canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
if (canon_change) {
- memset(&tty->read_flags, 0, sizeof tty->read_flags);
- tty->canon_head = tty->read_tail;
- tty->canon_data = 0;
- tty->erasing = 0;
+ bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
+ ldata->canon_head = ldata->read_tail;
+ ldata->canon_data = 0;
+ ldata->erasing = 0;
}
- if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+ if (canon_change && !L_ICANON(tty) && ldata->read_cnt)
wake_up_interruptible(&tty->read_wait);
- tty->icanon = (L_ICANON(tty) != 0);
+ ldata->icanon = (L_ICANON(tty) != 0);
if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
- tty->raw = 1;
- tty->real_raw = 1;
+ ldata->raw = 1;
+ ldata->real_raw = 1;
n_tty_set_room(tty);
return;
}
@@ -1496,51 +1540,51 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
I_PARMRK(tty)) {
- memset(tty->process_char_map, 0, 256/8);
+ bitmap_zero(ldata->process_char_map, 256);
if (I_IGNCR(tty) || I_ICRNL(tty))
- set_bit('\r', tty->process_char_map);
+ set_bit('\r', ldata->process_char_map);
if (I_INLCR(tty))
- set_bit('\n', tty->process_char_map);
+ set_bit('\n', ldata->process_char_map);
if (L_ICANON(tty)) {
- set_bit(ERASE_CHAR(tty), tty->process_char_map);
- set_bit(KILL_CHAR(tty), tty->process_char_map);
- set_bit(EOF_CHAR(tty), tty->process_char_map);
- set_bit('\n', tty->process_char_map);
- set_bit(EOL_CHAR(tty), tty->process_char_map);
+ set_bit(ERASE_CHAR(tty), ldata->process_char_map);
+ set_bit(KILL_CHAR(tty), ldata->process_char_map);
+ set_bit(EOF_CHAR(tty), ldata->process_char_map);
+ set_bit('\n', ldata->process_char_map);
+ set_bit(EOL_CHAR(tty), ldata->process_char_map);
if (L_IEXTEN(tty)) {
set_bit(WERASE_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
set_bit(LNEXT_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
set_bit(EOL2_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
if (L_ECHO(tty))
set_bit(REPRINT_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
}
}
if (I_IXON(tty)) {
- set_bit(START_CHAR(tty), tty->process_char_map);
- set_bit(STOP_CHAR(tty), tty->process_char_map);
+ set_bit(START_CHAR(tty), ldata->process_char_map);
+ set_bit(STOP_CHAR(tty), ldata->process_char_map);
}
if (L_ISIG(tty)) {
- set_bit(INTR_CHAR(tty), tty->process_char_map);
- set_bit(QUIT_CHAR(tty), tty->process_char_map);
- set_bit(SUSP_CHAR(tty), tty->process_char_map);
+ set_bit(INTR_CHAR(tty), ldata->process_char_map);
+ set_bit(QUIT_CHAR(tty), ldata->process_char_map);
+ set_bit(SUSP_CHAR(tty), ldata->process_char_map);
}
- clear_bit(__DISABLED_CHAR, tty->process_char_map);
- tty->raw = 0;
- tty->real_raw = 0;
+ clear_bit(__DISABLED_CHAR, ldata->process_char_map);
+ ldata->raw = 0;
+ ldata->real_raw = 0;
} else {
- tty->raw = 1;
+ ldata->raw = 1;
if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
(I_IGNPAR(tty) || !I_INPCK(tty)) &&
(tty->driver->flags & TTY_DRIVER_REAL_RAW))
- tty->real_raw = 1;
+ ldata->real_raw = 1;
else
- tty->real_raw = 0;
+ ldata->real_raw = 0;
}
n_tty_set_room(tty);
/* The termios change make the tty ready for I/O */
@@ -1560,15 +1604,13 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
static void n_tty_close(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
n_tty_flush_buffer(tty);
- if (tty->read_buf) {
- kfree(tty->read_buf);
- tty->read_buf = NULL;
- }
- if (tty->echo_buf) {
- kfree(tty->echo_buf);
- tty->echo_buf = NULL;
- }
+ kfree(ldata->read_buf);
+ kfree(ldata->echo_buf);
+ kfree(ldata);
+ tty->disc_data = NULL;
}
/**
@@ -1583,37 +1625,50 @@ static void n_tty_close(struct tty_struct *tty)
static int n_tty_open(struct tty_struct *tty)
{
- if (!tty)
- return -EINVAL;
+ struct n_tty_data *ldata;
+
+ ldata = kzalloc(sizeof(*ldata), GFP_KERNEL);
+ if (!ldata)
+ goto err;
+
+ ldata->overrun_time = jiffies;
+ mutex_init(&ldata->atomic_read_lock);
+ mutex_init(&ldata->output_lock);
+ mutex_init(&ldata->echo_lock);
+ spin_lock_init(&ldata->read_lock);
/* These are ugly. Currently a malloc failure here can panic */
- if (!tty->read_buf) {
- tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
- if (!tty->read_buf)
- return -ENOMEM;
- }
- if (!tty->echo_buf) {
- tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ ldata->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ if (!ldata->read_buf || !ldata->echo_buf)
+ goto err_free_bufs;
- if (!tty->echo_buf)
- return -ENOMEM;
- }
+ tty->disc_data = ldata;
reset_buffer_flags(tty);
tty_unthrottle(tty);
- tty->column = 0;
+ ldata->column = 0;
n_tty_set_termios(tty, NULL);
tty->minimum_to_wake = 1;
tty->closing = 0;
+
return 0;
+err_free_bufs:
+ kfree(ldata->read_buf);
+ kfree(ldata->echo_buf);
+ kfree(ldata);
+err:
+ return -ENOMEM;
}
static inline int input_available_p(struct tty_struct *tty, int amt)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
tty_flush_to_ldisc(tty);
- if (tty->icanon && !L_EXTPROC(tty)) {
- if (tty->canon_data)
+ if (ldata->icanon && !L_EXTPROC(tty)) {
+ if (ldata->canon_data)
return 1;
- } else if (tty->read_cnt >= (amt ? amt : 1))
+ } else if (ldata->read_cnt >= (amt ? amt : 1))
return 1;
return 0;
@@ -1632,7 +1687,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
* buffer, and once to drain the space from the (physical) beginning of
* the buffer to head pointer.
*
- * Called under the tty->atomic_read_lock sem
+ * Called under the ldata->atomic_read_lock sem
*
*/
@@ -1641,29 +1696,31 @@ static int copy_from_read_buf(struct tty_struct *tty,
size_t *nr)
{
+ struct n_tty_data *ldata = tty->disc_data;
int retval;
size_t n;
unsigned long flags;
bool is_eof;
retval = 0;
- spin_lock_irqsave(&tty->read_lock, flags);
- n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);
n = min(*nr, n);
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (n) {
- retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
+ retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
n -= retval;
is_eof = n == 1 &&
- tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
- tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt -= n;
+ ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty);
+ tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
+ ldata->icanon);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt -= n;
/* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
+ if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
n = 0;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
*b += n;
*nr -= n;
}
@@ -1730,6 +1787,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t nr)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned char __user *b = buf;
DECLARE_WAITQUEUE(wait, current);
int c;
@@ -1741,17 +1799,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
int packet;
do_it_again:
-
- if (WARN_ON(!tty->read_buf))
- return -EAGAIN;
-
c = job_control(tty, file);
if (c < 0)
return c;
minimum = time = 0;
timeout = MAX_SCHEDULE_TIMEOUT;
- if (!tty->icanon) {
+ if (!ldata->icanon) {
time = (HZ / 10) * TIME_CHAR(tty);
minimum = MIN_CHAR(tty);
if (minimum) {
@@ -1774,10 +1828,10 @@ do_it_again:
* Internal serialization of reads.
*/
if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&tty->atomic_read_lock))
+ if (!mutex_trylock(&ldata->atomic_read_lock))
return -EAGAIN;
} else {
- if (mutex_lock_interruptible(&tty->atomic_read_lock))
+ if (mutex_lock_interruptible(&ldata->atomic_read_lock))
return -ERESTARTSYS;
}
packet = tty->packet;
@@ -1830,7 +1884,6 @@ do_it_again:
/* FIXME: does n_tty_set_room need locking ? */
n_tty_set_room(tty);
timeout = schedule_timeout(timeout);
- BUG_ON(!tty->read_buf);
continue;
}
__set_current_state(TASK_RUNNING);
@@ -1845,45 +1898,45 @@ do_it_again:
nr--;
}
- if (tty->icanon && !L_EXTPROC(tty)) {
+ if (ldata->icanon && !L_EXTPROC(tty)) {
/* N.B. avoid overrun if nr == 0 */
- spin_lock_irqsave(&tty->read_lock, flags);
- while (nr && tty->read_cnt) {
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ while (nr && ldata->read_cnt) {
int eol;
- eol = test_and_clear_bit(tty->read_tail,
- tty->read_flags);
- c = tty->read_buf[tty->read_tail];
- tty->read_tail = ((tty->read_tail+1) &
+ eol = test_and_clear_bit(ldata->read_tail,
+ ldata->read_flags);
+ c = ldata->read_buf[ldata->read_tail];
+ ldata->read_tail = ((ldata->read_tail+1) &
(N_TTY_BUF_SIZE-1));
- tty->read_cnt--;
+ ldata->read_cnt--;
if (eol) {
/* this test should be redundant:
* we shouldn't be reading data if
* canon_data is 0
*/
- if (--tty->canon_data < 0)
- tty->canon_data = 0;
+ if (--ldata->canon_data < 0)
+ ldata->canon_data = 0;
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
if (tty_put_user(tty, c, b++)) {
retval = -EFAULT;
b--;
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
break;
}
nr--;
}
if (eol) {
tty_audit_push(tty);
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
break;
}
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (retval)
break;
} else {
@@ -1915,7 +1968,7 @@ do_it_again:
if (time)
timeout = time;
}
- mutex_unlock(&tty->atomic_read_lock);
+ mutex_unlock(&ldata->atomic_read_lock);
remove_wait_queue(&tty->read_wait, &wait);
if (!waitqueue_active(&tty->read_wait))
@@ -2076,19 +2129,19 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
return mask;
}
-static unsigned long inq_canon(struct tty_struct *tty)
+static unsigned long inq_canon(struct n_tty_data *ldata)
{
int nr, head, tail;
- if (!tty->canon_data)
+ if (!ldata->canon_data)
return 0;
- head = tty->canon_head;
- tail = tty->read_tail;
+ head = ldata->canon_head;
+ tail = ldata->read_tail;
nr = (head - tail) & (N_TTY_BUF_SIZE-1);
/* Skip EOF-chars.. */
while (head != tail) {
- if (test_bit(tail, tty->read_flags) &&
- tty->read_buf[tail] == __DISABLED_CHAR)
+ if (test_bit(tail, ldata->read_flags) &&
+ ldata->read_buf[tail] == __DISABLED_CHAR)
nr--;
tail = (tail+1) & (N_TTY_BUF_SIZE-1);
}
@@ -2098,6 +2151,7 @@ static unsigned long inq_canon(struct tty_struct *tty)
static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct n_tty_data *ldata = tty->disc_data;
int retval;
switch (cmd) {
@@ -2105,9 +2159,9 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
/* FIXME: Locking */
- retval = tty->read_cnt;
+ retval = ldata->read_cnt;
if (L_ICANON(tty))
- retval = inq_canon(tty);
+ retval = inq_canon(ldata);
return put_user(retval, (unsigned int __user *) arg);
default:
return n_tty_ioctl_helper(tty, file, cmd, arg);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a82b399..4219f04 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -4,9 +4,6 @@
* Added support for a Unix98-style ptmx device.
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
*
- * When reading this code see also fs/devpts. In particular note that the
- * driver_data field is used by the devpts side as a binding to the devpts
- * inode.
*/
#include <linux/module.h>
@@ -59,7 +56,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
#ifdef CONFIG_UNIX98_PTYS
if (tty->driver == ptm_driver) {
mutex_lock(&devpts_mutex);
- devpts_pty_kill(tty->link);
+ devpts_pty_kill(tty->link->driver_data);
mutex_unlock(&devpts_mutex);
}
#endif
@@ -96,7 +93,7 @@ static void pty_unthrottle(struct tty_struct *tty)
static int pty_space(struct tty_struct *to)
{
- int n = 8192 - to->buf.memory_used;
+ int n = 8192 - to->port->buf.memory_used;
if (n < 0)
return 0;
return n;
@@ -348,6 +345,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
tty_port_init(ports[1]);
o_tty->port = ports[0];
tty->port = ports[1];
+ o_tty->port->itty = o_tty;
tty_driver_kref_get(driver);
tty->count++;
@@ -366,8 +364,15 @@ err:
return retval;
}
+/* this is called once with whichever end is closed last */
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+ devpts_kill_index(tty->driver_data, tty->index);
+}
+
static void pty_cleanup(struct tty_struct *tty)
{
+ tty->port->itty = NULL;
kfree(tty->port);
}
@@ -547,7 +552,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
struct tty_struct *tty;
mutex_lock(&devpts_mutex);
- tty = devpts_get_tty(pts_inode, idx);
+ tty = devpts_get_priv(pts_inode);
mutex_unlock(&devpts_mutex);
/* Master must be open before slave */
if (!tty)
@@ -581,6 +586,7 @@ static const struct tty_operations ptm_unix98_ops = {
.set_termios = pty_set_termios,
.ioctl = pty_unix98_ioctl,
.resize = pty_resize,
+ .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup
};
@@ -596,6 +602,7 @@ static const struct tty_operations pty_unix98_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
+ .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup,
};
@@ -614,6 +621,7 @@ static const struct tty_operations pty_unix98_ops = {
static int ptmx_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
+ struct inode *slave_inode;
int retval;
int index;
@@ -650,15 +658,21 @@ static int ptmx_open(struct inode *inode, struct file *filp)
tty_add_file(tty, filp);
- retval = devpts_pty_new(inode, tty->link);
- if (retval)
+ slave_inode = devpts_pty_new(inode,
+ MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
+ tty->link);
+ if (IS_ERR(slave_inode)) {
+ retval = PTR_ERR(slave_inode);
goto err_release;
+ }
retval = ptm_driver->ops->open(tty, filp);
if (retval)
goto err_release;
tty_unlock(tty);
+ tty->driver_data = inode;
+ tty->link->driver_data = slave_inode;
return 0;
err_release:
tty_unlock(tty);
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 3ba4234..5ccbd90 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -2349,16 +2349,14 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
-#ifdef CONFIG_ARCH_OMAP1
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
- if (cpu_is_omap1510() && is_omap_port(up)) {
+ if (is_omap1510_8250(up)) {
if (baud == 115200) {
quot = 1;
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
} else
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
}
-#endif
/*
* For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
@@ -2439,10 +2437,9 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
if (pt->port.iotype == UPIO_AU)
return 0x1000;
-#ifdef CONFIG_ARCH_OMAP1
- if (is_omap_port(pt))
+ if (is_omap1_8250(pt))
return 0x16 << pt->port.regshift;
-#endif
+
return 8 << pt->port.regshift;
}
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 5a76f9c..3b4ea84 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -106,3 +106,39 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { }
#endif
+#ifdef CONFIG_ARCH_OMAP1
+static inline int is_omap1_8250(struct uart_8250_port *pt)
+{
+ int res;
+
+ switch (pt->port.mapbase) {
+ case OMAP1_UART1_BASE:
+ case OMAP1_UART2_BASE:
+ case OMAP1_UART3_BASE:
+ res = 1;
+ break;
+ default:
+ res = 0;
+ break;
+ }
+
+ return res;
+}
+
+static inline int is_omap1510_8250(struct uart_8250_port *pt)
+{
+ if (!cpu_is_omap1510())
+ return 0;
+
+ return is_omap1_8250(pt);
+}
+#else
+static inline int is_omap1_8250(struct uart_8250_port *pt)
+{
+ return 0;
+}
+static inline int is_omap1510_8250(struct uart_8250_port *pt)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index eaafb98..843a150 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -140,7 +140,7 @@ static void __init init_port(struct early_serial8250_device *device)
serial_out(port, UART_FCR, 0); /* no fifo */
serial_out(port, UART_MCR, 0x3); /* DTR + RTS */
- divisor = port->uartclk / (16 * device->baud);
+ divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
c = serial_in(port, UART_LCR);
serial_out(port, UART_LCR, c | UART_LCR_DLAB);
serial_out(port, UART_DLL, divisor & 0xff);
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 7f04717..740458c 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -530,16 +530,16 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
switch (level) {
case 3:
if (!IS_ERR(ourport->baudclk))
- clk_disable(ourport->baudclk);
+ clk_disable_unprepare(ourport->baudclk);
- clk_disable(ourport->clk);
+ clk_disable_unprepare(ourport->clk);
break;
case 0:
- clk_enable(ourport->clk);
+ clk_prepare_enable(ourport->clk);
if (!IS_ERR(ourport->baudclk))
- clk_enable(ourport->baudclk);
+ clk_prepare_enable(ourport->baudclk);
break;
default:
@@ -713,11 +713,11 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
s3c24xx_serial_setsource(port, clk_sel);
if (!IS_ERR(ourport->baudclk)) {
- clk_disable(ourport->baudclk);
+ clk_disable_unprepare(ourport->baudclk);
ourport->baudclk = ERR_PTR(-EINVAL);
}
- clk_enable(clk);
+ clk_prepare_enable(clk);
ourport->baudclk = clk;
ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
@@ -1287,9 +1287,9 @@ static int s3c24xx_serial_resume(struct device *dev)
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (port) {
- clk_enable(ourport->clk);
+ clk_prepare_enable(ourport->clk);
s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
- clk_disable(ourport->clk);
+ clk_disable_unprepare(ourport->clk);
uart_resume_port(&s3c24xx_uart_drv, port);
}
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index b0b39b8..6953dc8 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -23,7 +23,7 @@ struct tty_audit_buf {
};
static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
- int icanon)
+ unsigned icanon)
{
struct tty_audit_buf *buf;
@@ -239,7 +239,8 @@ int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
* if TTY auditing is disabled or out of memory. Otherwise, return a new
* reference to the buffer.
*/
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
+static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
+ unsigned icanon)
{
struct tty_audit_buf *buf, *buf2;
@@ -257,7 +258,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
buf2 = tty_audit_buf_alloc(tty->driver->major,
tty->driver->minor_start + tty->index,
- tty->icanon);
+ icanon);
if (buf2 == NULL) {
audit_log_lost("out of memory in TTY auditing");
return NULL;
@@ -287,7 +288,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
* Audit @data of @size from @tty, if necessary.
*/
void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
- size_t size)
+ size_t size, unsigned icanon)
{
struct tty_audit_buf *buf;
int major, minor;
@@ -299,7 +300,7 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
&& tty->driver->subtype == PTY_TYPE_MASTER)
return;
- buf = tty_audit_buf_get(tty);
+ buf = tty_audit_buf_get(tty, icanon);
if (!buf)
return;
@@ -307,11 +308,11 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
major = tty->driver->major;
minor = tty->driver->minor_start + tty->index;
if (buf->major != major || buf->minor != minor
- || buf->icanon != tty->icanon) {
+ || buf->icanon != icanon) {
tty_audit_buf_push_current(buf);
buf->major = major;
buf->minor = minor;
- buf->icanon = tty->icanon;
+ buf->icanon = icanon;
}
do {
size_t run;
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 91e326f..6cf87d7 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -27,19 +27,21 @@
* Locking: none
*/
-void tty_buffer_free_all(struct tty_struct *tty)
+void tty_buffer_free_all(struct tty_port *port)
{
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *thead;
- while ((thead = tty->buf.head) != NULL) {
- tty->buf.head = thead->next;
+
+ while ((thead = buf->head) != NULL) {
+ buf->head = thead->next;
kfree(thead);
}
- while ((thead = tty->buf.free) != NULL) {
- tty->buf.free = thead->next;
+ while ((thead = buf->free) != NULL) {
+ buf->free = thead->next;
kfree(thead);
}
- tty->buf.tail = NULL;
- tty->buf.memory_used = 0;
+ buf->tail = NULL;
+ buf->memory_used = 0;
}
/**
@@ -54,11 +56,11 @@ void tty_buffer_free_all(struct tty_struct *tty)
* Locking: Caller must hold tty->buf.lock
*/
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
{
struct tty_buffer *p;
- if (tty->buf.memory_used + size > 65536)
+ if (port->buf.memory_used + size > 65536)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
if (p == NULL)
@@ -70,7 +72,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
p->read = 0;
p->char_buf_ptr = (char *)(p->data);
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
- tty->buf.memory_used += size;
+ port->buf.memory_used += size;
return p;
}
@@ -85,17 +87,19 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
* Locking: Caller must hold tty->buf.lock
*/
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
{
+ struct tty_bufhead *buf = &port->buf;
+
/* Dumb strategy for now - should keep some stats */
- tty->buf.memory_used -= b->size;
- WARN_ON(tty->buf.memory_used < 0);
+ buf->memory_used -= b->size;
+ WARN_ON(buf->memory_used < 0);
if (b->size >= 512)
kfree(b);
else {
- b->next = tty->buf.free;
- tty->buf.free = b;
+ b->next = buf->free;
+ buf->free = b;
}
}
@@ -110,15 +114,16 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
* Locking: Caller must hold tty->buf.lock
*/
-static void __tty_buffer_flush(struct tty_struct *tty)
+static void __tty_buffer_flush(struct tty_port *port)
{
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *thead;
- while ((thead = tty->buf.head) != NULL) {
- tty->buf.head = thead->next;
- tty_buffer_free(tty, thead);
+ while ((thead = buf->head) != NULL) {
+ buf->head = thead->next;
+ tty_buffer_free(port, thead);
}
- tty->buf.tail = NULL;
+ buf->tail = NULL;
}
/**
@@ -134,21 +139,24 @@ static void __tty_buffer_flush(struct tty_struct *tty)
void tty_buffer_flush(struct tty_struct *tty)
{
+ struct tty_port *port = tty->port;
+ struct tty_bufhead *buf = &port->buf;
unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
+
+ spin_lock_irqsave(&buf->lock, flags);
/* If the data is being pushed to the tty layer then we can't
process it here. Instead set a flag and the flush_to_ldisc
path will process the flush request before it exits */
- if (test_bit(TTY_FLUSHING, &tty->flags)) {
- set_bit(TTY_FLUSHPENDING, &tty->flags);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ if (test_bit(TTYP_FLUSHING, &port->iflags)) {
+ set_bit(TTYP_FLUSHPENDING, &port->iflags);
+ spin_unlock_irqrestore(&buf->lock, flags);
wait_event(tty->read_wait,
- test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+ test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0);
return;
} else
- __tty_buffer_flush(tty);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ __tty_buffer_flush(port);
+ spin_unlock_irqrestore(&buf->lock, flags);
}
/**
@@ -163,9 +171,9 @@ void tty_buffer_flush(struct tty_struct *tty)
* Locking: Caller must hold tty->buf.lock
*/
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size)
{
- struct tty_buffer **tbh = &tty->buf.free;
+ struct tty_buffer **tbh = &port->buf.free;
while ((*tbh) != NULL) {
struct tty_buffer *t = *tbh;
if (t->size >= size) {
@@ -174,14 +182,14 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
t->used = 0;
t->commit = 0;
t->read = 0;
- tty->buf.memory_used += t->size;
+ port->buf.memory_used += t->size;
return t;
}
tbh = &((*tbh)->next);
}
/* Round the buffer size out */
size = (size + 0xFF) & ~0xFF;
- return tty_buffer_alloc(tty, size);
+ return tty_buffer_alloc(port, size);
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
@@ -192,29 +200,31 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
- * Locking: Caller must hold tty->buf.lock
+ * Locking: Caller must hold port->buf.lock
*/
-static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_port *port, size_t size)
{
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *b, *n;
int left;
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
- if ((b = tty->buf.tail) != NULL)
+ b = buf->tail;
+ if (b != NULL)
left = b->size - b->used;
else
left = 0;
if (left < size) {
/* This is the slow path - looking for new buffers to use */
- if ((n = tty_buffer_find(tty, size)) != NULL) {
+ if ((n = tty_buffer_find(port, size)) != NULL) {
if (b != NULL) {
b->next = n;
b->commit = b->used;
} else
- tty->buf.head = n;
- tty->buf.tail = n;
+ buf->head = n;
+ buf->tail = n;
} else
size = left;
}
@@ -231,16 +241,17 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
*
- * Locking: Takes tty->buf.lock
+ * Locking: Takes port->buf.lock
*/
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
+ struct tty_port *port = tty->port;
unsigned long flags;
int length;
- spin_lock_irqsave(&tty->buf.lock, flags);
- length = __tty_buffer_request_room(tty, size);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_lock_irqsave(&port->buf.lock, flags);
+ length = __tty_buffer_request_room(port, size);
+ spin_unlock_irqrestore(&port->buf.lock, flags);
return length;
}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
@@ -255,12 +266,13 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
* Queue a series of bytes to the tty buffering. All the characters
* passed are marked with the supplied flag. Returns the number added.
*
- * Locking: Called functions may take tty->buf.lock
+ * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
const unsigned char *chars, char flag, size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
@@ -268,18 +280,18 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
unsigned long flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, flags);
- space = __tty_buffer_request_room(tty, goal);
- tb = tty->buf.tail;
+ spin_lock_irqsave(&buf->lock, flags);
+ space = __tty_buffer_request_room(tty->port, goal);
+ tb = buf->tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0)) {
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
@@ -300,12 +312,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
* the flags array indicates the status of the character. Returns the
* number added.
*
- * Locking: Called functions may take tty->buf.lock
+ * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_flags(struct tty_struct *tty,
const unsigned char *chars, const char *flags, size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
@@ -313,18 +326,18 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
unsigned long __flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, __flags);
- space = __tty_buffer_request_room(tty, goal);
- tb = tty->buf.tail;
+ spin_lock_irqsave(&buf->lock, __flags);
+ space = __tty_buffer_request_room(tty->port, goal);
+ tb = buf->tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0)) {
- spin_unlock_irqrestore(&tty->buf.lock, __flags);
+ spin_unlock_irqrestore(&buf->lock, __flags);
break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memcpy(tb->flag_buf_ptr + tb->used, flags, space);
tb->used += space;
- spin_unlock_irqrestore(&tty->buf.lock, __flags);
+ spin_unlock_irqrestore(&buf->lock, __flags);
copied += space;
chars += space;
flags += space;
@@ -342,18 +355,23 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
* Takes any pending buffers and transfers their ownership to the
* ldisc side of the queue. It then schedules those characters for
* processing by the line discipline.
+ * Note that this function can only be used when the low_latency flag
+ * is unset. Otherwise the workqueue won't be flushed.
*
- * Locking: Takes tty->buf.lock
+ * Locking: Takes port->buf.lock
*/
void tty_schedule_flip(struct tty_struct *tty)
{
+ struct tty_bufhead *buf = &tty->port->buf;
unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL)
- tty->buf.tail->commit = tty->buf.tail->used;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
- schedule_work(&tty->buf.work);
+ WARN_ON(tty->low_latency);
+
+ spin_lock_irqsave(&buf->lock, flags);
+ if (buf->tail != NULL)
+ buf->tail->commit = buf->tail->used;
+ spin_unlock_irqrestore(&buf->lock, flags);
+ schedule_work(&buf->work);
}
EXPORT_SYMBOL(tty_schedule_flip);
@@ -369,26 +387,27 @@ EXPORT_SYMBOL(tty_schedule_flip);
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
*
- * Locking: May call functions taking tty->buf.lock
+ * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
- size_t size)
+ size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int space;
unsigned long flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, flags);
- space = __tty_buffer_request_room(tty, size);
+ spin_lock_irqsave(&buf->lock, flags);
+ space = __tty_buffer_request_room(tty->port, size);
- tb = tty->buf.tail;
+ tb = buf->tail;
if (likely(space)) {
*chars = tb->char_buf_ptr + tb->used;
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
tb->used += space;
}
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -406,26 +425,27 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
*
- * Locking: May call functions taking tty->buf.lock
+ * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int space;
unsigned long __flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, __flags);
- space = __tty_buffer_request_room(tty, size);
+ spin_lock_irqsave(&buf->lock, __flags);
+ space = __tty_buffer_request_room(tty->port, size);
- tb = tty->buf.tail;
+ tb = buf->tail;
if (likely(space)) {
*chars = tb->char_buf_ptr + tb->used;
*flags = tb->flag_buf_ptr + tb->used;
tb->used += space;
}
- spin_unlock_irqrestore(&tty->buf.lock, __flags);
+ spin_unlock_irqrestore(&buf->lock, __flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
@@ -446,20 +466,25 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
static void flush_to_ldisc(struct work_struct *work)
{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, buf.work);
+ struct tty_port *port = container_of(work, struct tty_port, buf.work);
+ struct tty_bufhead *buf = &port->buf;
+ struct tty_struct *tty;
unsigned long flags;
struct tty_ldisc *disc;
+ tty = port->itty;
+ if (WARN_RATELIMIT(tty == NULL, "tty is NULL"))
+ return;
+
disc = tty_ldisc_ref(tty);
if (disc == NULL) /* !TTY_LDISC */
return;
- spin_lock_irqsave(&tty->buf.lock, flags);
+ spin_lock_irqsave(&buf->lock, flags);
- if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
+ if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
struct tty_buffer *head;
- while ((head = tty->buf.head) != NULL) {
+ while ((head = buf->head) != NULL) {
int count;
char *char_buf;
unsigned char *flag_buf;
@@ -468,14 +493,14 @@ static void flush_to_ldisc(struct work_struct *work)
if (!count) {
if (head->next == NULL)
break;
- tty->buf.head = head->next;
- tty_buffer_free(tty, head);
+ buf->head = head->next;
+ tty_buffer_free(port, head);
continue;
}
/* Ldisc or user is trying to flush the buffers
we are feeding to the ldisc, stop feeding the
line discipline as we want to empty the queue */
- if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+ if (test_bit(TTYP_FLUSHPENDING, &port->iflags))
break;
if (!tty->receive_room)
break;
@@ -484,22 +509,22 @@ static void flush_to_ldisc(struct work_struct *work)
char_buf = head->char_buf_ptr + head->read;
flag_buf = head->flag_buf_ptr + head->read;
head->read += count;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
disc->ops->receive_buf(tty, char_buf,
flag_buf, count);
- spin_lock_irqsave(&tty->buf.lock, flags);
+ spin_lock_irqsave(&buf->lock, flags);
}
- clear_bit(TTY_FLUSHING, &tty->flags);
+ clear_bit(TTYP_FLUSHING, &port->iflags);
}
/* We may have a deferred request to flush the input buffer,
if so pull the chain under the lock and empty the queue */
- if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
- __tty_buffer_flush(tty);
- clear_bit(TTY_FLUSHPENDING, &tty->flags);
+ if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
+ __tty_buffer_flush(port);
+ clear_bit(TTYP_FLUSHPENDING, &port->iflags);
wake_up(&tty->read_wait);
}
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
tty_ldisc_deref(disc);
}
@@ -514,7 +539,8 @@ static void flush_to_ldisc(struct work_struct *work)
*/
void tty_flush_to_ldisc(struct tty_struct *tty)
{
- flush_work(&tty->buf.work);
+ if (!tty->low_latency)
+ flush_work(&tty->port->buf.work);
}
/**
@@ -532,16 +558,18 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
void tty_flip_buffer_push(struct tty_struct *tty)
{
+ struct tty_bufhead *buf = &tty->port->buf;
unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL)
- tty->buf.tail->commit = tty->buf.tail->used;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+ spin_lock_irqsave(&buf->lock, flags);
+ if (buf->tail != NULL)
+ buf->tail->commit = buf->tail->used;
+ spin_unlock_irqrestore(&buf->lock, flags);
if (tty->low_latency)
- flush_to_ldisc(&tty->buf.work);
+ flush_to_ldisc(&buf->work);
else
- schedule_work(&tty->buf.work);
+ schedule_work(&buf->work);
}
EXPORT_SYMBOL(tty_flip_buffer_push);
@@ -555,13 +583,15 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
* Locking: none
*/
-void tty_buffer_init(struct tty_struct *tty)
+void tty_buffer_init(struct tty_port *port)
{
- spin_lock_init(&tty->buf.lock);
- tty->buf.head = NULL;
- tty->buf.tail = NULL;
- tty->buf.free = NULL;
- tty->buf.memory_used = 0;
- INIT_WORK(&tty->buf.work, flush_to_ldisc);
+ struct tty_bufhead *buf = &port->buf;
+
+ spin_lock_init(&buf->lock);
+ buf->head = NULL;
+ buf->tail = NULL;
+ buf->free = NULL;
+ buf->memory_used = 0;
+ INIT_WORK(&buf->work, flush_to_ldisc);
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 2ea176b..a3eba7f 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -186,7 +186,6 @@ void free_tty_struct(struct tty_struct *tty)
if (tty->dev)
put_device(tty->dev);
kfree(tty->write_buf);
- tty_buffer_free_all(tty);
tty->magic = 0xDEADDEAD;
kfree(tty);
}
@@ -1417,6 +1416,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
"%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
__func__, tty->driver->name);
+ tty->port->itty = tty;
+
/*
* Structures all installed ... call the ldisc open routines.
* If we fail here just call release_tty to clean up. No need
@@ -1552,6 +1553,7 @@ static void release_tty(struct tty_struct *tty, int idx)
tty->ops->shutdown(tty);
tty_free_termios(tty);
tty_driver_remove_tty(tty->driver, tty);
+ tty->port->itty = NULL;
if (tty->link)
tty_kref_put(tty->link);
@@ -1625,7 +1627,6 @@ int tty_release(struct inode *inode, struct file *filp)
struct tty_struct *tty = file_tty(filp);
struct tty_struct *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep;
- int devpts;
int idx;
char buf[64];
@@ -1640,7 +1641,6 @@ int tty_release(struct inode *inode, struct file *filp)
idx = tty->index;
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER);
- devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
/* Review: parallel close */
o_tty = tty->link;
@@ -1799,9 +1799,6 @@ int tty_release(struct inode *inode, struct file *filp)
release_tty(tty, idx);
mutex_unlock(&tty_mutex);
- /* Make this pty number available for reallocation */
- if (devpts)
- devpts_kill_index(inode, idx);
return 0;
}
@@ -2937,19 +2934,13 @@ void initialize_tty_struct(struct tty_struct *tty,
tty_ldisc_init(tty);
tty->session = NULL;
tty->pgrp = NULL;
- tty->overrun_time = jiffies;
- tty_buffer_init(tty);
mutex_init(&tty->legacy_mutex);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
- mutex_init(&tty->atomic_read_lock);
mutex_init(&tty->atomic_write_lock);
- mutex_init(&tty->output_lock);
- mutex_init(&tty->echo_lock);
- spin_lock_init(&tty->read_lock);
spin_lock_init(&tty->ctrl_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 0f2a2c5..f4e6754 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -512,7 +512,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
static int tty_ldisc_halt(struct tty_struct *tty)
{
clear_bit(TTY_LDISC, &tty->flags);
- return cancel_work_sync(&tty->buf.work);
+ return cancel_work_sync(&tty->port->buf.work);
}
/**
@@ -525,7 +525,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
{
flush_work(&tty->hangup_work);
flush_work(&tty->SAK_work);
- flush_work(&tty->buf.work);
+ flush_work(&tty->port->buf.work);
}
/**
@@ -704,9 +704,9 @@ enable:
/* Restart the work queue in case no characters kick it off. Safe if
already running */
if (work)
- schedule_work(&tty->buf.work);
+ schedule_work(&tty->port->buf.work);
if (o_work)
- schedule_work(&o_tty->buf.work);
+ schedule_work(&o_tty->port->buf.work);
mutex_unlock(&tty->ldisc_mutex);
tty_unlock(tty);
return retval;
@@ -817,7 +817,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
*/
clear_bit(TTY_LDISC, &tty->flags);
tty_unlock(tty);
- cancel_work_sync(&tty->buf.work);
+ cancel_work_sync(&tty->port->buf.work);
mutex_unlock(&tty->ldisc_mutex);
retry:
tty_lock(tty);
@@ -897,6 +897,11 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
static void tty_ldisc_kill(struct tty_struct *tty)
{
+ /* There cannot be users from userspace now. But there still might be
+ * drivers holding a reference via tty_ldisc_ref. Do not steal them the
+ * ldisc until they are done. */
+ tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT);
+
mutex_lock(&tty->ldisc_mutex);
/*
* Now kill off the ldisc
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index d7bdd8d..416b42f 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -21,6 +21,7 @@
void tty_port_init(struct tty_port *port)
{
memset(port, 0, sizeof(*port));
+ tty_buffer_init(port);
init_waitqueue_head(&port->open_wait);
init_waitqueue_head(&port->close_wait);
init_waitqueue_head(&port->delta_msr_wait);
@@ -126,6 +127,7 @@ static void tty_port_destructor(struct kref *kref)
struct tty_port *port = container_of(kref, struct tty_port, kref);
if (port->xmit_buf)
free_page((unsigned long)port->xmit_buf);
+ tty_buffer_free_all(port);
if (port->ops->destruct)
port->ops->destruct(port);
else
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 8e9b4be..60b7b69 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -341,15 +341,11 @@ int paste_selection(struct tty_struct *tty)
struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current);
-
console_lock();
poke_blanked_console();
console_unlock();
- /* FIXME: wtf is this supposed to achieve ? */
- ld = tty_ldisc_ref(tty);
- if (!ld)
- ld = tty_ldisc_ref_wait(tty);
+ ld = tty_ldisc_ref_wait(tty);
/* FIXME: this is completely unsafe */
add_wait_queue(&vc->paste_wait, &wait);
@@ -361,8 +357,7 @@ int paste_selection(struct tty_struct *tty)
}
count = sel_buffer_lth - pasted;
count = min(count, tty->receive_room);
- tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
- NULL, count);
+ ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count);
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
OpenPOWER on IntegriCloud