Improve input flow control.

Use input buffer watermarks of TTYHOG-512 (high) and (high)*7/8
(low) instead of TTYHOG/2 (high) and TTYHOG/5 (low) to agree with
some drivers.  512 is magic and some things depended on TTYHOG/2
>= TTYHOG-512 to work; now they depend on the 512 magic not changing
and TTYHOG-512 being significantly larger than 0.  This should be
handled in ttsetwater().

Separate the decision about whether to do input flow control from
doing it.  ttyblock() now just starts input flow control (hardware
and/or software) and there is a new function ttyunblock() to stop
it.  The decisions are the same except for the watermark changes
and allowing for input expansion for PARMRK.

When flushing input, try harder at first to send a start character
if required, but give up if the first attempt fails.

cy.c, rc.c, sio.c:
Simplify: let ttyinput() handle input flow control if it is not
being bypassed.  Use ttyblock() to start flow control otherwise.

rc.c:
Use same input flow control test as elsewhere: test in a more
efficient order and start flow control at >= highwater instead of
at > highwater.
This commit is contained in:
Bruce Evans 1995-07-31 18:29:51 +00:00
parent cca80d1fd8
commit f3b37f91c1
10 changed files with 126 additions and 249 deletions

View File

@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: cy.c,v 1.12 1995/07/29 04:05:53 bde Exp $
* $Id: cy.c,v 1.13 1995/07/29 08:33:06 bde Exp $
*/
#include "cy.h"
@ -1598,31 +1598,6 @@ siopoll()
}
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
* XXX only do this when we bypass ttyinput.
*/
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK)
/*
* XXX - need flow control for all line disciplines.
* Only have it in standard one now.
*/
&& linesw[tp->t_line].l_rint == ttyinput) {
int putc_status = 0;
if ((tp->t_iflag & IXOFF
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
&& (putc_status = putc(tp->t_cc[VSTOP],
&tp->t_outq)) == 0)
|| com->state & CS_RTS_IFLOW) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (putc_status != 0)
/* Try again later. */
tp->t_state &= ~TS_TBLOCK;
}
}
/*
* Avoid the grotesquely inefficient lineswitch routine
* (ttyinput) in "raw" mode. It usually takes about 450
@ -1631,6 +1606,11 @@ siopoll()
* call overhead).
*/
if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW
|| tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += incc;
tk_rawcc += incc;
tp->t_rawcc += incc;

View File

@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: cy.c,v 1.12 1995/07/29 04:05:53 bde Exp $
* $Id: cy.c,v 1.13 1995/07/29 08:33:06 bde Exp $
*/
#include "cy.h"
@ -1598,31 +1598,6 @@ siopoll()
}
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
* XXX only do this when we bypass ttyinput.
*/
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK)
/*
* XXX - need flow control for all line disciplines.
* Only have it in standard one now.
*/
&& linesw[tp->t_line].l_rint == ttyinput) {
int putc_status = 0;
if ((tp->t_iflag & IXOFF
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
&& (putc_status = putc(tp->t_cc[VSTOP],
&tp->t_outq)) == 0)
|| com->state & CS_RTS_IFLOW) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (putc_status != 0)
/* Try again later. */
tp->t_state &= ~TS_TBLOCK;
}
}
/*
* Avoid the grotesquely inefficient lineswitch routine
* (ttyinput) in "raw" mode. It usually takes about 450
@ -1631,6 +1606,11 @@ siopoll()
* call overhead).
*/
if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW
|| tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += incc;
tk_rawcc += incc;
tp->t_rawcc += incc;

View File

@ -664,24 +664,12 @@ void rcpoll()
if (icnt <= 0 || !(tp->t_state & TS_ISOPEN))
goto done1;
if ( linesw[tp->t_line].l_rint == ttyinput
&& ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))
&& !(tp->t_state & TS_TBLOCK)
&& (tp->t_rawq.c_cc + icnt) > RB_I_HIGH_WATER) {
int queue_full = 0;
if ((tp->t_iflag & IXOFF) &&
tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
(queue_full = putc(tp->t_cc[VSTOP], &tp->t_outq)) == 0 ||
(rc->rc_flags & RC_RTSFLOW)) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (queue_full) /* try again */
tp->t_state &= ~TS_TBLOCK;
}
}
if ( (tp->t_state & TS_CAN_BYPASS_L_RINT)
&& !(tp->t_state & TS_LOCAL)) {
if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER
&& ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += icnt;
tk_rawcc += icnt;
tp->t_rawcc += icnt;

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
* $Id: sio.c,v 1.106 1995/07/29 04:05:57 bde Exp $
* $Id: sio.c,v 1.107 1995/07/29 08:33:13 bde Exp $
*/
#include "sio.h"
@ -1547,31 +1547,6 @@ siopoll()
}
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
* XXX only do this when we bypass ttyinput.
*/
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK)
/*
* XXX - need flow control for all line disciplines.
* Only have it in standard one now.
*/
&& linesw[tp->t_line].l_rint == ttyinput) {
int putc_status = 0;
if ((tp->t_iflag & IXOFF
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
&& (putc_status = putc(tp->t_cc[VSTOP],
&tp->t_outq)) == 0)
|| com->state & CS_RTS_IFLOW) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (putc_status != 0)
/* Try again later. */
tp->t_state &= ~TS_TBLOCK;
}
}
/*
* Avoid the grotesquely inefficient lineswitch routine
* (ttyinput) in "raw" mode. It usually takes about 450
@ -1580,6 +1555,11 @@ siopoll()
* call overhead).
*/
if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW
|| tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += incc;
tk_rawcc += incc;
tp->t_rawcc += incc;

View File

@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: cy.c,v 1.12 1995/07/29 04:05:53 bde Exp $
* $Id: cy.c,v 1.13 1995/07/29 08:33:06 bde Exp $
*/
#include "cy.h"
@ -1598,31 +1598,6 @@ siopoll()
}
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
* XXX only do this when we bypass ttyinput.
*/
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK)
/*
* XXX - need flow control for all line disciplines.
* Only have it in standard one now.
*/
&& linesw[tp->t_line].l_rint == ttyinput) {
int putc_status = 0;
if ((tp->t_iflag & IXOFF
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
&& (putc_status = putc(tp->t_cc[VSTOP],
&tp->t_outq)) == 0)
|| com->state & CS_RTS_IFLOW) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (putc_status != 0)
/* Try again later. */
tp->t_state &= ~TS_TBLOCK;
}
}
/*
* Avoid the grotesquely inefficient lineswitch routine
* (ttyinput) in "raw" mode. It usually takes about 450
@ -1631,6 +1606,11 @@ siopoll()
* call overhead).
*/
if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW
|| tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += incc;
tk_rawcc += incc;
tp->t_rawcc += incc;

View File

@ -664,24 +664,12 @@ void rcpoll()
if (icnt <= 0 || !(tp->t_state & TS_ISOPEN))
goto done1;
if ( linesw[tp->t_line].l_rint == ttyinput
&& ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))
&& !(tp->t_state & TS_TBLOCK)
&& (tp->t_rawq.c_cc + icnt) > RB_I_HIGH_WATER) {
int queue_full = 0;
if ((tp->t_iflag & IXOFF) &&
tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
(queue_full = putc(tp->t_cc[VSTOP], &tp->t_outq)) == 0 ||
(rc->rc_flags & RC_RTSFLOW)) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (queue_full) /* try again */
tp->t_state &= ~TS_TBLOCK;
}
}
if ( (tp->t_state & TS_CAN_BYPASS_L_RINT)
&& !(tp->t_state & TS_LOCAL)) {
if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER
&& ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += icnt;
tk_rawcc += icnt;
tp->t_rawcc += icnt;

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
* $Id: sio.c,v 1.106 1995/07/29 04:05:57 bde Exp $
* $Id: sio.c,v 1.107 1995/07/29 08:33:13 bde Exp $
*/
#include "sio.h"
@ -1547,31 +1547,6 @@ siopoll()
}
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
* XXX only do this when we bypass ttyinput.
*/
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK)
/*
* XXX - need flow control for all line disciplines.
* Only have it in standard one now.
*/
&& linesw[tp->t_line].l_rint == ttyinput) {
int putc_status = 0;
if ((tp->t_iflag & IXOFF
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
&& (putc_status = putc(tp->t_cc[VSTOP],
&tp->t_outq)) == 0)
|| com->state & CS_RTS_IFLOW) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (putc_status != 0)
/* Try again later. */
tp->t_state &= ~TS_TBLOCK;
}
}
/*
* Avoid the grotesquely inefficient lineswitch routine
* (ttyinput) in "raw" mode. It usually takes about 450
@ -1580,6 +1555,11 @@ siopoll()
* call overhead).
*/
if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW
|| tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += incc;
tk_rawcc += incc;
tp->t_rawcc += incc;

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
* $Id: sio.c,v 1.106 1995/07/29 04:05:57 bde Exp $
* $Id: sio.c,v 1.107 1995/07/29 08:33:13 bde Exp $
*/
#include "sio.h"
@ -1547,31 +1547,6 @@ siopoll()
}
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
* XXX only do this when we bypass ttyinput.
*/
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK)
/*
* XXX - need flow control for all line disciplines.
* Only have it in standard one now.
*/
&& linesw[tp->t_line].l_rint == ttyinput) {
int putc_status = 0;
if ((tp->t_iflag & IXOFF
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
&& (putc_status = putc(tp->t_cc[VSTOP],
&tp->t_outq)) == 0)
|| com->state & CS_RTS_IFLOW) {
tp->t_state |= TS_TBLOCK;
ttstart(tp);
if (putc_status != 0)
/* Try again later. */
tp->t_state &= ~TS_TBLOCK;
}
}
/*
* Avoid the grotesquely inefficient lineswitch routine
* (ttyinput) in "raw" mode. It usually takes about 450
@ -1580,6 +1555,11 @@ siopoll()
* call overhead).
*/
if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
&& (com->state & CS_RTS_IFLOW
|| tp->t_iflag & IXOFF)
&& !(tp->t_state & TS_TBLOCK))
ttyblock(tp);
tk_nin += incc;
tk_rawcc += incc;
tp->t_rawcc += incc;

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)tty.c 8.8 (Berkeley) 1/21/94
* $Id: tty.c,v 1.59 1995/07/30 12:39:16 bde Exp $
* $Id: tty.c,v 1.60 1995/07/30 13:52:56 bde Exp $
*/
/*-
@ -95,9 +95,9 @@
static int proc_compare __P((struct proc *p1, struct proc *p2));
static int ttnread __P((struct tty *));
static void ttyblock __P((struct tty *tp));
static void ttyecho __P((int, struct tty *tp));
static void ttyrubo __P((struct tty *, int));
static void ttyunblock __P((struct tty *tp));
/*
* Table with character classes and parity. The 8th bit indicates parity,
@ -177,6 +177,14 @@ char const char_type[] = {
#define CLR(t, f) (t) &= ~(f)
#define ISSET(t, f) ((t) & (f))
/*
* Input control starts when we would not be able to fit the maximum
* contents of the ping-pong buffers and finishes when we would be able
* to fit that much plus 1/8 more.
*/
#define I_HIGH_WATER (TTYHOG - 2 * 256) /* XXX */
#define I_LOW_WATER ((TTYHOG - 2 * 256) * 7 / 8) /* XXX */
#undef MAX_INPUT /* XXX wrong in <sys/syslimits.h> */
#define MAX_INPUT TTYHOG
@ -285,9 +293,21 @@ ttyinput(c, tp)
}
++tk_nin;
/*
* Block further input iff:
* current input > threshold AND input is available to user program
* AND input flow control is enabled and not yet invoked.
* The 3 is slop for PARMRK.
*/
iflag = tp->t_iflag;
if (tp->t_rawq.c_cc + tp->t_canq.c_cc > I_HIGH_WATER - 3 &&
(!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) &&
(ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) &&
!ISSET(tp->t_state, TS_TBLOCK))
ttyblock(tp);
/* Handle exceptional conditions (break, parity, framing). */
cc = tp->t_cc;
iflag = tp->t_iflag;
err = (ISSET(c, TTY_ERRORMASK));
if (err) {
CLR(c, TTY_ERRORMASK);
@ -317,11 +337,7 @@ ttyinput(c, tp)
c = 0;
}
}
/*
* In tandem mode, check high water mark.
*/
if (ISSET(iflag, IXOFF) || ISSET(tp->t_cflag, CRTS_IFLOW))
ttyblock(tp);
if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
CLR(c, 0x80);
if (!ISSET(lflag, EXTPROC)) {
@ -1109,6 +1125,7 @@ ttyflush(tp, rw)
register int s;
s = spltty();
again:
if (rw & FWRITE)
CLR(tp->t_state, TS_TTSTOP);
#ifdef sun4c /* XXX */
@ -1123,25 +1140,33 @@ ttyflush(tp, rw)
tp->t_rocol = 0;
CLR(tp->t_state, TS_LOCAL);
ttwakeup(tp);
if (ISSET(tp->t_state, TS_TBLOCK)) {
ttyunblock(tp);
if (ISSET(tp->t_iflag, IXOFF)) {
/*
* XXX wait a bit in the hope that the stop
* character (if any) will go out. Waiting
* isn't good since it allows races. This
* will be fixed when the stop character is
* put in a special queue. Don't bother with
* the checks in ttywait() since the timeout
* will save us.
*/
SET(tp->t_state, TS_SO_OCOMPLETE);
ttysleep(tp, TSA_OCOMPLETE(tp), TTOPRI,
"ttyfls", hz / 10);
/*
* Don't try sending the stop character again.
*/
CLR(tp->t_state, TS_TBLOCK);
goto again;
}
}
}
if (rw & FWRITE) {
FLUSHQ(&tp->t_outq);
ttwwakeup(tp);
}
if ((rw & FREAD) &&
ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
int queue_full = 0;
if (ISSET(tp->t_iflag, IXOFF) &&
tp->t_cc[VSTART] != _POSIX_VDISABLE &&
(queue_full = putc(tp->t_cc[VSTART], &tp->t_outq)) == 0 ||
ISSET(tp->t_cflag, CRTS_IFLOW)) {
CLR(tp->t_state, TS_TBLOCK);
ttstart(tp);
if (queue_full) /* try again */
SET(tp->t_state, TS_TBLOCK);
}
}
splx(s);
}
@ -1168,34 +1193,37 @@ ttychars(tp)
}
/*
* Send stop character on input overflow.
* Handle input high water. Send stop character for the IXOFF case. Turn
* on our input flow control bit and propagate the changes to the driver.
* XXX the stop character should be put in a special high priority queue.
*/
void
ttyblock(tp)
struct tty *tp;
{
SET(tp->t_state, TS_TBLOCK);
if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
putc(tp->t_cc[VSTOP], &tp->t_outq) != 0)
CLR(tp->t_state, TS_TBLOCK); /* try again later */
ttstart(tp);
}
/*
* Handle input low water. Send start character for the IXOFF case. Turn
* off our input flow control bit and propagate the changes to the driver.
* XXX the start character should be put in a special high priority queue.
*/
static void
ttyblock(tp)
register struct tty *tp;
ttyunblock(tp)
struct tty *tp;
{
register int total;
total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
/*
* Block further input iff: current input > threshold
* AND input is available to user program.
*/
if (total >= TTYHOG / 2 &&
!ISSET(tp->t_state, TS_TBLOCK) &&
(!ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0)) {
int queue_full = 0;
if (ISSET(tp->t_iflag, IXOFF) &&
tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
(queue_full = putc(tp->t_cc[VSTOP], &tp->t_outq)) == 0 ||
ISSET(tp->t_cflag, CRTS_IFLOW)) {
SET(tp->t_state, TS_TBLOCK);
ttstart(tp);
if (queue_full) /* try again */
CLR(tp->t_state, TS_TBLOCK);
}
}
CLR(tp->t_state, TS_TBLOCK);
if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE &&
putc(tp->t_cc[VSTART], &tp->t_outq) != 0)
SET(tp->t_state, TS_TBLOCK); /* try again later */
ttstart(tp);
}
void
@ -1590,26 +1618,18 @@ ttread(tp, uio, flag)
break;
first = 0;
}
out:
/*
* Look to unblock input now that (presumably)
* the input queue has gone down.
*/
out:
s = spltty();
if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
int queue_full = 0;
if (ISSET(tp->t_iflag, IXOFF) &&
cc[VSTART] != _POSIX_VDISABLE &&
(queue_full = putc(cc[VSTART], &tp->t_outq)) == 0 ||
ISSET(tp->t_cflag, CRTS_IFLOW)) {
CLR(tp->t_state, TS_TBLOCK);
ttstart(tp);
if (queue_full) /* try again */
SET(tp->t_state, TS_TBLOCK);
}
}
if (ISSET(tp->t_state, TS_TBLOCK) &&
tp->t_rawq.c_cc + tp->t_canq.c_cc <= I_LOW_WATER)
ttyunblock(tp);
splx(s);
return (error);
}

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)tty.h 8.6 (Berkeley) 1/21/94
* $Id: tty.h,v 1.25 1995/07/29 13:40:13 bde Exp $
* $Id: tty.h,v 1.26 1995/07/30 12:39:42 bde Exp $
*/
#ifndef _SYS_TTY_H_
@ -241,6 +241,7 @@ int ttstart __P((struct tty *tp));
void ttwakeup __P((struct tty *tp));
int ttwrite __P((struct tty *tp, struct uio *uio, int flag));
void ttwwakeup __P((struct tty *tp));
void ttyblock __P((struct tty *tp));
void ttychars __P((struct tty *tp));
int ttycheckoutq __P((struct tty *tp, int wait));
int ttyclose __P((struct tty *tp));