diff options
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r-- | drivers/tty/n_tty.c | 752 |
1 files changed, 403 insertions, 349 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 8c0b7b42319..19083efa231 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\n"); + 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); |