patch-2.1.72 linux/drivers/char/n_tty.c
Next file: linux/drivers/char/rtc.c
Previous file: linux/drivers/char/acquirewdt.c
Back to the patch index
Back to the overall index
- Lines: 274
- Date:
Sat Dec 6 11:26:26 1997
- Orig file:
v2.1.71/linux/drivers/char/n_tty.c
- Orig date:
Thu Dec 4 14:53:55 1997
diff -u --recursive --new-file v2.1.71/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
@@ -54,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)
@@ -66,21 +66,42 @@
}
}
+/*
+ * 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);
@@ -508,7 +529,7 @@
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);
@@ -611,11 +632,29 @@
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)
@@ -670,28 +709,17 @@
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)
@@ -786,10 +814,8 @@
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;
@@ -798,7 +824,7 @@
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))
@@ -825,7 +851,8 @@
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;
@@ -868,7 +895,7 @@
}
}
- if (L_ICANON(tty)) {
+ if (tty->icanon) {
minimum = time = 0;
current->timeout = (unsigned long) -1;
} else {
@@ -897,9 +924,10 @@
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;
}
@@ -937,50 +965,52 @@
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;
@@ -1048,6 +1078,10 @@
tty->driver.flush_chars(tty);
} else {
c = tty->driver.write(tty, 1, b, nr);
+ if (c < 0) {
+ retval = c;
+ break;
+ }
b += c;
nr -= c;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov