summaryrefslogtreecommitdiffstats
path: root/drivers/char/n_tty.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
commit967c65a99059fd459b956c1588ce0ba227912c4e (patch)
tree8224d013ff5d255420713d05610c7efebd204d2a /drivers/char/n_tty.c
parente20c1cc1656a66a2773bca4591a895cbc12696ff (diff)
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'drivers/char/n_tty.c')
-rw-r--r--drivers/char/n_tty.c159
1 files changed, 98 insertions, 61 deletions
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 3581b81c3..251f73f96 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -40,6 +40,7 @@
#include <asm/bitops.h>
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
+#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -53,7 +54,7 @@
* unthrottling the TTY driver. These watermarks are used for
* controlling the space in the read buffer.
*/
-#define TTY_THRESHOLD_THROTTLE (N_TTY_BUF_SIZE - 128)
+#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
#define TTY_THRESHOLD_UNTHROTTLE 128
static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
@@ -65,21 +66,42 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
}
}
+/*
+ * Check whether to call the driver.unthrottle function.
+ * We test the TTY_THROTTLED bit first so that it always
+ * indicates the current state.
+ */
+static void check_unthrottle(struct tty_struct * tty)
+{
+ if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->driver.unthrottle)
+ tty->driver.unthrottle(tty);
+}
+
/*
- * Flush the input buffer
+ * Reset the read buffer counters, clear the flags,
+ * and make sure the driver is unthrottled. Called
+ * from n_tty_open() and n_tty_flush_buffer().
*/
-void n_tty_flush_buffer(struct tty_struct * tty)
+static void reset_buffer_flags(struct tty_struct *tty)
{
tty->read_head = tty->read_tail = tty->read_cnt = 0;
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->read_flags, 0, sizeof tty->read_flags);
+ check_unthrottle(tty);
+}
+
+/*
+ * Flush the input buffer
+ */
+void n_tty_flush_buffer(struct tty_struct * tty)
+{
+ /* clear everything and unthrottle the driver */
+ reset_buffer_flags(tty);
if (!tty->link)
return;
- if (tty->driver.unthrottle &&
- test_and_clear_bit(TTY_THROTTLED, &tty->flags))
- tty->driver.unthrottle(tty);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->read_wait);
@@ -507,7 +529,7 @@ send_signal:
return;
}
}
- if (L_ICANON(tty)) {
+ if (tty->icanon) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
@@ -610,11 +632,29 @@ send_signal:
put_tty_queue(c, tty);
}
+static int n_tty_receive_room(struct tty_struct *tty)
+{
+ int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+ /*
+ * If we are doing input canonicalization, and there are no
+ * pending newlines, let characters through without limit, so
+ * that erase characters will be handled. Other excess
+ * characters will be beeped.
+ */
+ if (tty->icanon && !tty->canon_data)
+ return N_TTY_BUF_SIZE;
+
+ if (left > 0)
+ return left;
+ return 0;
+}
+
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
const unsigned char *p;
- char *f, flags = 0;
+ char *f, flags = TTY_NORMAL;
int i;
if (!tty->read_buf)
@@ -669,34 +709,23 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
wake_up_interruptible(&tty->read_wait);
}
- if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
- tty->driver.throttle &&
- !test_and_set_bit(TTY_THROTTLED, &tty->flags))
- tty->driver.throttle(tty);
-}
-
-static int n_tty_receive_room(struct tty_struct *tty)
-{
- int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
/*
- * If we are doing input canonicalization, and there are no
- * pending newlines, let characters through without limit, so
- * that erase characters will be handled. Other excess
- * characters will be beeped.
+ * Check the remaining room for the input canonicalization
+ * mode. We don't want to throttle the driver if we're in
+ * canonical mode and don't have a newline yet!
*/
- if (tty->icanon && !tty->canon_data)
- return N_TTY_BUF_SIZE;
-
- if (left > 0)
- return left;
- return 0;
+ if (n_tty_receive_room(tty) < TTY_THRESHOLD_THROTTLE) {
+ /* check TTY_THROTTLED first so it indicates our state */
+ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->driver.throttle)
+ tty->driver.throttle(tty);
+ }
}
int is_ignored(int sig)
{
- return ((current->blocked & (1<<(sig-1))) ||
- (current->sig->action[sig-1].sa_handler == SIG_IGN));
+ return (sigismember(&current->blocked, sig) ||
+ current->sig->action[sig-1].sa.sa_handler == SIG_IGN);
}
static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
@@ -785,10 +814,8 @@ static int n_tty_open(struct tty_struct *tty)
return -ENOMEM;
}
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
- tty->read_head = tty->read_tail = tty->read_cnt = 0;
- tty->canon_head = tty->canon_data = tty->erasing = 0;
+ reset_buffer_flags(tty);
tty->column = 0;
- memset(tty->read_flags, 0, sizeof(tty->read_flags));
n_tty_set_termios(tty, 0);
tty->minimum_to_wake = 1;
tty->closing = 0;
@@ -797,7 +824,7 @@ static int n_tty_open(struct tty_struct *tty)
static inline int input_available_p(struct tty_struct *tty, int amt)
{
- if (L_ICANON(tty)) {
+ if (tty->icanon) {
if (tty->canon_data)
return 1;
} else if (tty->read_cnt >= (amt ? amt : 1))
@@ -824,7 +851,8 @@ static inline void copy_from_read_buf(struct tty_struct *tty,
n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
if (!n)
return;
- copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
+ /* N.B. copy_to_user may work only partially */
+ n -= copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
*b += n;
@@ -854,6 +882,7 @@ do_it_again:
check of the logic of this change. -- jlc */
/* don't stop on /dev/console */
if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
+ file->f_dentry->d_inode->i_rdev != SYSCONS_DEV &&
current->tty == tty) {
if (tty->pgrp <= 0)
printk("read_chan: tty->pgrp <= 0!\n");
@@ -866,7 +895,7 @@ do_it_again:
}
}
- if (L_ICANON(tty)) {
+ if (tty->icanon) {
minimum = time = 0;
current->timeout = (unsigned long) -1;
} else {
@@ -895,9 +924,10 @@ do_it_again:
while (1) {
/* First test for status change. */
if (tty->packet && tty->link->ctrl_status) {
- if (b != buf)
+ if (b != buf || !nr)
break;
put_user(tty->link->ctrl_status, b++);
+ nr--;
tty->link->ctrl_status = 0;
break;
}
@@ -935,50 +965,52 @@ do_it_again:
current->state = TASK_RUNNING;
/* Deal with packet mode. */
- if (tty->packet && b == buf) {
+ if (tty->packet && b == buf && nr) {
put_user(TIOCPKT_DATA, b++);
nr--;
}
- if (L_ICANON(tty)) {
- while (1) {
- int eol;
+ if (tty->icanon) {
+ /* N.B. avoid overrun if nr == 0 */
+ while (nr && tty->read_cnt) {
+ int eol;
- if (!tty->read_cnt) {
- break;
- }
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) &
(N_TTY_BUF_SIZE-1));
tty->read_cnt--;
- if (!eol) {
- put_user(c, b++);
- if (--nr)
- continue;
- break;
- }
- if (--tty->canon_data < 0) {
- tty->canon_data = 0;
- }
- if (c != __DISABLED_CHAR) {
+
+ if (!eol || (c != __DISABLED_CHAR)) {
put_user(c, b++);
nr--;
}
- break;
+ 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;
+ break;
+ }
}
} else {
+ /* N.B. check for errors writing to user space? */
copy_from_read_buf(tty, &b, &nr);
copy_from_read_buf(tty, &b, &nr);
}
/* If there is enough space in the read buffer now, let the
- low-level driver know. */
- if (tty->driver.unthrottle &&
- (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
- && test_and_clear_bit(TTY_THROTTLED, &tty->flags))
- tty->driver.unthrottle(tty);
+ * low-level driver know. We use n_tty_chars_in_buffer() to
+ * check the buffer, as it now knows about canonical mode.
+ * Otherwise, if the driver is throttled and the line is
+ * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
+ * we won't get any more characters.
+ */
+ if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
+ check_unthrottle(tty);
if (b - buf >= minimum || !nr)
break;
@@ -1012,7 +1044,8 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
ssize_t retval = 0, num;
/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
- if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV) {
+ if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
+ file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
retval = tty_check_change(tty);
if (retval)
return retval;
@@ -1045,6 +1078,10 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
tty->driver.flush_chars(tty);
} else {
c = tty->driver.write(tty, 1, b, nr);
+ if (c < 0) {
+ retval = c;
+ break;
+ }
b += c;
nr -= c;
}