|
|
coherent
/*
* File: $USRSRC/ttydrv/tty.c
*
* Purpose: COHERENT line discipline module.
* This is the common part of typewriter service. It handles all device-
* independent aspects of a typewriter, including tandem flow control,
* erase and kill, stop and start, and common ioctl functions.
*
* $Log: tty.c,v $
* Revision 1.1.1.1 2019/05/29 04:56:39 root
* coherent
*
* Revision 1.15 92/01/13 08:58:40 bin
* update by hal for 321 kernel (looks like just additions of debug stuff)
*
* Revision 1.15 92/01/13 08:36:53 hal
* Add a few DEBUG lines.
*
* Revision 1.14 92/01/09 09:42:31 hal
* Add debug conditionals for sleeps.
* Fix process group logic, including TIOCSETG hack.
*
* Revision 1.13 91/12/10 17:01:56 hal
* Don't wait for drain on TIOCFLUSH.
*
* Revision 1.12 91/11/14 14:28:51 hal
* Move flow control out of tty.c.
* Make ttin() run at hi priority.
*
* Revision 1.11 91/09/16 18:11:08 hal
* Update t_flags in ttstart() at high priority.
* Document that ttstash() is local.
*
* Revision 1.10 91/09/16 15:58:26 hal
* Mask interrrupts when modifying tp->t_flags as some IRQ handlers change this.
*
* Revision 1.9 91/09/16 10:27:47 hal
* Explain T_ISTOP/T_TSTOP/T_STOP.
* Add check for TANDEM before sending t_startc.
*
* Revision 1.8 91/09/13 18:01:39 piggy
* Only do XON/XOFF flow control if TANDEM is set.
*
* Revision 1.7 91/09/13 17:58:00 hal
* Drop 3rd arg (was writing PSW directly from it!) for ttread/ttwrite.
* General face lift.
*
* Bug: no support for 8-bit characters.
* Fix: don't strip keyboard input. 01/22/91. (norm)
*
* Bug: Switching modes between cooked and CBREAK/RAW left buffered input
* in the input buffer until returning to cooked mode. 05/13/91 norm
*
* Bug: setting speed to default in ttopen() was conditioned to
* use hard constants. 90/08/28. hws
*
* Revision 1.5 91/06/06 18:28:53 norm
* Restore 8-bit fix.
*
* Revision 1.2 89/07/17 11:51:20 src
* Bug: Terminal could lock up when setting it to RAWIN mode, if
* output was suspended due to X-OFF, and output data was present.
* Fix: Setting terminal to RAWIN mode now clears X-OFF, starts output
* BEFORE waiting for output to drain. Received signals now cause
* operation to complete without waiting for drain. (ABC)
*
* Revision 1.1 88/03/24 16:18:12 src
* Initial revision
*
* 86/12/12 Allan Cornish /usr/src/sys/drv/tty.c
* Added 3rd argument to ttpoll() to support non-blocking polls.
*
* 86/11/19 Allan Cornish /usr/src/sys/drv/tty.c
* Made ttread() and ttwrite() recognize the IONDLY flag in iop->io_flag.
* wakeup() and pollwake() now have delayed invocation by defer().
* Added poll [System V.3] capability.
*
* 85/06/28 Allan Cornish
* made ttioctl() clear T_STOP flag if ISRIN.
*
* 85/03/04 Allan Cornish
* made ttread() interruptible.
*
* 85/03/01 Allan Cornish
* made ttclose() interruptible.
*/
/*
* About STOP flag bits:
* T_ISTOP is set when the tty module's input queue is in danger of
* overflow. It is up to the device driver to check this flag
* and do something about it. If ttin() is called with a
* character from the device while T_ISTOP is set, the character
* is discarded. T_ISTOP is cleared when the input queue is
* sufficiently empty. The device driver can monitor this bit for
* hardware flow control.
* T_TSTOP is the "Tandem" flow control flag for input. If TANDEM is set
* and the input queue is in danger of overflow, t_stopc is sent
* and T_TSTOP is set. When the input queue is empty enough,
* t_startc is sent and T_TSTOP is cleared.
* T_STOP is the flow control bit for output. No output will be
* written to the output queue while this bit is true.
* Except for initialization of flags in the TTY struct, by
* ttopen(), this bit is not written by tty.c.
* 91/09/15 - hal
*/
/*
* Includes.
*/
#include <sys/clist.h>
#include <sys/coherent.h>
#include <sys/con.h>
#include <sys/deftty.h>
#include <sys/io.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/stat.h>
#include <sys/tty.h>
#include <sys/uproc.h>
#include <errno.h>
/*
* Definitions.
* Constants.
* Macros with argument lists.
* Typedefs.
* Enums.
*/
/* NEAR_OR_FAR_CALL is for invoking t_param and t_start */
#define NEAR_OR_FAR_CALL(tp_fn) {\
if (tp->t_cs_sel) \
ld_call(tp->t_cs_sel, tp->tp_fn, tp); \
else \
(*tp->tp_fn)(tp); }
/*
* Functions.
* Import Functions.
* Export Functions.
* Local Functions.
*/
void ttclose();
void ttflush();
void tthup();
void ttin();
void ttioctl();
void ttopen();
int ttout();
int ttpoll();
void ttread();
void ttsetgrp();
void ttsignal();
void ttstart();
void ttwrite();
static void ttstash();
/*
* Global Data.
* Import Variables.
* Export Variables.
* Local Variables.
*/
extern int wakeup();
extern void pollwake();
/*
* ttopen()
*
* Called by driver on first open.
* Set up defaults.
*/
void ttopen(tp)
register TTY *tp;
{
tp->t_escape = 0;
tp->t_sgttyb.sg_ispeed = tp->t_dispeed;
tp->t_sgttyb.sg_ospeed = tp->t_dospeed;
tp->t_sgttyb.sg_erase = DEF_SG_ERASE;
tp->t_sgttyb.sg_kill = DEF_SG_KILL;
tp->t_sgttyb.sg_flags = DEF_SG_FLAGS;
tp->t_tchars.t_intrc = DEF_T_INTRC;
tp->t_tchars.t_quitc = DEF_T_QUITC;
tp->t_tchars.t_startc = DEF_T_STARTC;
tp->t_tchars.t_stopc = DEF_T_STOPC;
tp->t_tchars.t_eofc = DEF_T_EOFC;
tp->t_tchars.t_brkc = DEF_T_BRKC;
if (tp->t_param != NULL) {
NEAR_OR_FAR_CALL(t_param)
}
}
/*
* ttsetgrp()
*
* If process is a group leader without a control terminal,
* make its control terminal this device.
*
* If process is a group leader and this device does not have
* a process group, give it the group of the current process.
*/
void ttsetgrp(tp, ctdev)
register TTY *tp;
dev_t ctdev;
{
register PROC *pp;
pp = SELF;
#if DEBUG
printf("ttsetgrp dev=%x pid=%d pg=%d ", ctdev, pp->p_pid, pp->p_group);
printf("old_ct=%x old_tg=%d ", pp->p_ttdev, tp->t_group);
#endif
if (pp->p_group == pp->p_pid) {
if (pp->p_ttdev == NODEV)
pp->p_ttdev = ctdev;
if (tp->t_group == 0)
tp->t_group = pp->p_pid;
}
#if DEBUG
printf("new_ct=%x new_tg=%d\n", pp->p_ttdev, tp->t_group);
#endif
}
/*
* ttyclose()
*
* Called by driver on the last close.
* Wait for all pending output to go out.
* Kill input.
*/
void ttclose(tp)
register TTY *tp;
{
register int s;
while (tp->t_oq.cq_cc != 0) {
s = sphi();
if (tp->t_oq.cq_cc != 0) {
tp->t_flags |= T_DRAIN;
#if DEBUG
printf("T1 ");
#endif
sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT);
#if DEBUG
printf("z ");
#endif
}
spl(s);
if (SELF->p_ssig && nondsig())
break;
}
ttflush(tp);
tp->t_flags = tp->t_group = 0;
}
/*
* ttread()
*
* The read routine for a tty device driver will call this function.
*
* Move data from tp->t_iq to io segment iop.
* Number of characters to copy is in iop->ioc.
*
* In cooked mode, copy up to the first newline or break character, or
* until the count runs out.
* In CBREAK or RAW modes, return when count runs out or when input clist
* is empty and we're returning at least one byte.
*/
void ttread(tp, iop)
register TTY *tp;
register IO *iop;
{
register c;
int o;
int sioc = iop->io_ioc; /* number of bytes to read */
while (iop->io_ioc) {
o = sphi();
while ((c = getq(&tp->t_iq)) < 0) {
if ((tp->t_flags & T_CARR) == 0) {
u.u_error = EIO; /* error since no carrier */
spl(o);
return;
}
/* If we're in CBREAK or RAW mode, and we don't */
/* have the special "blocking read" bit set for */
/* these modes, and we read at least one byte */
/* of input, return immediately, since we have */
/* run out of characters from the clist. */
if (ISBBYB && ((tp->t_flags & T_BRD) == 0)
&& iop->io_ioc < sioc) {
spl(o);
return;
}
/*
* Non-blocking reads.
* Tell user process to try again later.
*/
if (iop->io_flag & IONDLY) {
u.u_error = EAGAIN;
spl(o);
return;
}
tp->t_flags |= T_INPUT; /* wait for more data */
#if DEBUG
printf("T2 ");
#endif
sleep((char *)&tp->t_iq, CVTTIN, IVTTIN, SVTTIN);
#if DEBUG
printf("z ");
#endif
if (SELF->p_ssig && nondsig()) {
if (iop->io_ioc == sioc)
u.u_error = EINTR;
spl(o);
return;
}
}
/*
* Flow control - can we turn on input from the driver yet?
*/
if (tp->t_iq.cq_cc <= ILOLIM) {
if ((tp->t_flags&T_ISTOP) != 0)
tp->t_flags &= ~T_ISTOP;
if (ISTAND && (tp->t_flags&T_TSTOP) != 0) {
tp->t_flags &= ~T_TSTOP;
while (putq(&tp->t_oq, startc) < 0) {
ttstart(tp);
waitq();
}
ttstart(tp);
}
}
spl(o);
if (!ISBBYB && ISEOF)
return;
if (ioputc(c, iop) < 0)
return;
if (!ISBBYB && (c=='\n' || ISBRK))
return;
}
}
/*
* ttwrite()
*
* Write routine.
* Transfer stuff to the character list.
*/
void ttwrite(tp, iop)
register TTY *tp;
register IO *iop;
{
register c;
int o;
/*
* Non-blocking writes which can fit.
* NOTE: exhaustion of clists can still cause blocking writes.
*/
if ((iop->io_flag & IONDLY) && (OHILIM >= iop->io_ioc)) {
/*
* No room.
*/
if (tp->t_oq.cq_cc >= OHILIM-iop->io_ioc) {
u.u_error = EAGAIN;
return;
}
}
while ((c = iogetc(iop)) >= 0) {
if ((tp->t_flags & T_CARR) == 0) {
u.u_error = EIO; /* error since no carrier */
return;
}
o = sphi();
while (tp->t_oq.cq_cc >= OHILIM) {
ttstart(tp);
if (tp->t_oq.cq_cc < OHILIM)
break;
tp->t_flags |= T_HILIM;
#if DEBUG
printf("T3 ");
#endif
sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT);
#if DEBUG
printf("z ");
#endif
if (SELF->p_ssig && nondsig()) {
u.u_error = EINTR;
spl(o);
return;
}
}
while (putq(&tp->t_oq, c) < 0) {
ttstart(tp);
waitq();
}
spl(o);
}
o = sphi();
ttstart(tp);
spl(o);
}
/*
* ttioctl()
*
* This routine handles common typewriter ioctl functions.
* Note that flushing the stream now means drain the output
* and clear the input.
*/
void ttioctl(tp, com, vec)
register TTY *tp;
register struct sgttyb *vec;
{
register int flush = 0;
register int drain = 0;
register char *p1, *p2;
int s;
int rload = 0;
int was_bbyb = 0;
switch (com) {
case TIOCQUERY:
kucopy(&tp->t_iq.cq_cc, vec, sizeof(int));
break;
case TIOCGETP:
kucopy(&tp->t_sgttyb, vec, sizeof (struct sgttyb));
break;
case TIOCSETP:
++flush; /* flush input */
++drain; /* delay for output */
++rload;
ukcopy(vec, &tp->t_sgttyb, sizeof (struct sgttyb));
break;
case TIOCSETN:
was_bbyb = ISBBYB; /* previous mode */
++rload;
ukcopy(vec, &tp->t_sgttyb, sizeof (struct sgttyb));
if (!was_bbyb && ISBBYB && tp->t_ibx != 0) {
p1 = &tp->t_ib[0];
p2 = &tp->t_ib[tp->t_ibx];
while (p1 < p2)
#if NOT_8_BIT
putq(&tp->t_iq, (*p1++) & 0177);
#else
putq(&tp->t_iq, (*p1++));
#endif
tp->t_ibx = 0;
}
break;
case TIOCGETC:
kucopy(&tp->t_tchars, vec, sizeof (struct tchars));
break;
case TIOCSETC:
++rload;
++drain;
ukcopy(vec, &tp->t_tchars, sizeof (struct tchars));
break;
case TIOCEXCL:
s = sphi();
tp->t_flags |= T_EXCL;
spl(s);
break;
case TIOCNXCL:
s = sphi();
tp->t_flags &= ~T_EXCL;
spl(s);
break;
case TIOCHPCL: /* set hangup on last close */
s = sphi();
tp->t_flags |= T_HPCL;
spl(s);
break;
case TIOCCHPCL: /* don't hangup on last close */
if (!super()) /* only superuser may do this */
u.u_error = EPERM; /* not su */
else {
s = sphi();
tp->t_flags &= ~T_HPCL; /* turn off hangup bit */
spl(s);
}
break;
case TIOCGETTF: /* get tty flag word */
kucopy(&tp->t_flags, (unsigned *) vec, sizeof(unsigned));
break;
case TIOCFLUSH:
++flush; /* flush both input and output */
/* ++drain; Why? - hws - 91/11/22 */
break;
case TIOCBREAD: /* blocking read for CBREAK/RAW mode */
s = sphi();
tp->t_flags |= T_BRD;
spl(s);
break;
case TIOCCBREAD: /* turn off CBREAK/RAW blocking read mode */
s = sphi();
tp->t_flags &= ~T_BRD;
spl(s);
break;
/*
* The following is a hack so that the process group for /dev/console
* contains the current login shell running on it.
* Only expect /etc/init to use this ugliness.
*/
case TIOCSETG:
if (super())
tp->t_group = SELF->p_group;
break;
default:
u.u_error = EINVAL;
}
/*
* Wait for output to drain, or signal to arrive.
*/
if (drain != 0) {
/*
* Ensure output is enabled BEFORE waiting for output to drain.
*/
if (ISRIN && (tp->t_flags & T_STOP)) {
s = sphi();
tp->t_flags &= ~T_STOP;
ttstart(tp);
spl(s);
}
while (tp->t_oq.cq_cc != 0) {
s = sphi();
tp->t_flags |= T_DRAIN;
spl(s);
#if DEBUG
printf("T4 ");
#endif
sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT);
#if DEBUG
printf("z ");
#endif
if (SELF->p_ssig && nondsig())
break;
}
}
/*
* Flush input.
*/
if (flush != 0)
ttflush(tp);
/*
* Re-initialize hardware.
*/
if ((rload != 0) && (tp->t_param != NULL))
NEAR_OR_FAR_CALL(t_param)
}
/*
* ttpoll()
*
* Polling routine.
* [System V.3 Compatible]
*/
int ttpoll(tp, ev, msec)
register TTY * tp;
int ev;
int msec;
{
/*
* Priority polls not supported.
*/
ev &= ~POLLPRI;
/*
* Input poll with no data present.
*/
if ((ev & POLLIN) && (tp->t_iq.cq_cc == 0)) {
/*
* Blocking input poll.
*/
if (msec != 0)
pollopen(&tp->t_ipolls);
/*
* Second look to avoid interrupt race.
*/
if (tp->t_iq.cq_cc == 0)
ev &= ~POLLIN;
}
/*
* Output poll with no space.
*/
if ((ev & POLLOUT) && (tp->t_oq.cq_cc >= OLOLIM)) {
/*
* Blocking output poll.
*/
if (msec != 0)
pollopen(&tp->t_opolls);
/*
* Second look to avoid interrupt race.
*/
if (tp->t_oq.cq_cc >= OLOLIM)
ev &= ~POLLIN;
}
if (((ev & POLLIN) == 0) && ((tp->t_flags & T_CARR) == 0))
ev |= POLLHUP;
return ev;
}
/*
* ttout()
*
* Pull a character from the output queues of the typewriter.
* Doing fills, newline insert, tab expansion, etc.
*
* If the stream is empty return a -1.
* Called at high priority.
*/
int ttout(tp)
register TTY *tp;
{
register c;
if (tp->t_nfill) {
--tp->t_nfill;
c = tp->t_fillb;
} else if ((tp->t_flags&T_INL) != 0) {
tp->t_flags &= ~T_INL;
c = '\n';
} else {
if ((c=getq(&tp->t_oq)) < 0)
return -1;
if (!ISROUT) {
if (c=='\n' && ISCRMOD) {
tp->t_flags |= T_INL;
c = '\r';
} else if (c=='\t' && ISXTABS) {
tp->t_nfill = ~(tp->t_hpos|~07);
tp->t_fillb = ' ';
c = ' ';
}
}
}
if (!ISROUT) {
if (c == '\b') {
if (tp->t_hpos)
--tp->t_hpos;
} else if (c == '\r')
tp->t_hpos = 0;
else if (c == '\t')
tp->t_hpos = (tp->t_hpos|07) + 1;
#if NOT_8_BIT
else if (c >= ' ' && c <= '~')
#else
else if ((c >= ' ' && c <= '~') || (c >= 0200 && c <= 0376))
#endif
++tp->t_hpos;
}
return c;
}
/*
* ttin()
*
* Pass a character to the device independent typewriter routines.
* Handle erase and kill, tandem flow control, and other magic.
* Often called at high priority from the driver's interrupt routine.
*/
void ttin(tp, c)
register TTY *tp;
register c;
{
int dc, i, n;
int s;
if (!ISRIN) {
#if NOT_8_BIT
c &= 0177;
#endif
if (ISINTR) {
ttsignal(tp, SIGINT);
goto ttin_ret;
}
if (ISQUIT) {
ttsignal(tp, SIGQUIT);
goto ttin_ret;
}
}
if ((tp->t_flags&T_ISTOP) != 0)
goto ttin_ret;
if (!ISRIN) {
if (c=='\r' && ISCRMOD)
c = '\n';
if (tp->t_escape != 0) {
if (c == ESC)
++tp->t_escape;
else {
if (ISERASE || ISKILL) {
c |= 0200;
--tp->t_escape;
}
while (tp->t_escape!=0 && tp->t_ibx<NCIB-1) {
tp->t_ib[tp->t_ibx++] = ESC;
--tp->t_escape;
}
ttstash(tp, c);
}
if (ISECHO) {
#if NOT_8_BIT
putq(&tp->t_oq, c&0177);
#else
putq(&tp->t_oq, c); /* no strip for 8-bit */
#endif
ttstart(tp);
}
goto ttin_ret;
}
if (ISERASE && !ISCBRK) {
while (tp->t_escape!=0 && tp->t_ibx<NCIB-1) {
tp->t_ib[tp->t_ibx++] = ESC;
--tp->t_escape;
}
if (tp->t_ibx == 0)
goto ttin_ret;
dc = tp->t_ib[--tp->t_ibx];
if (ISECHO) {
if (!ISCRT)
putq(&tp->t_oq, c);
/* don't erase for bell, null, or rubout */
#if NOT_8_BIT
else if (((c = dc&0177) == '\007')
|| c == 0 || c == 0177)
#else
else if (((c = dc) == '\007')
|| c == 0 || c == 0177 || c == 0377)
#endif
goto ttin_ret;
else if (c != '\b' && c != '\t') {
putq(&tp->t_oq, '\b');
putq(&tp->t_oq, ' ');
putq(&tp->t_oq, '\b');
} else if (c == '\t') {
n = tp->t_opos + tp->t_escape;
for (i=0; i<tp->t_ibx; ++i) {
c = tp->t_ib[i];
#if NOT_8_BIT
if ((c&0200) != 0) {
++n;
c &= 0177;
}
#endif
if (c == '\b')
--n;
else {
if (c == '\t')
n |= 07;
++n;
}
}
while (n++ < tp->t_hpos)
putq(&tp->t_oq, '\b');
}
#if NOT_8_BIT
if ((dc&0200) != 0) {
if ((dc&0177) != '\b')
putq(&tp->t_oq, '\b');
putq(&tp->t_oq, ' ');
putq(&tp->t_oq, '\b');
}
#endif
ttstart(tp);
}
goto ttin_ret;
}
if (ISKILL && !ISCBRK) {
tp->t_ibx = 0;
tp->t_escape = 0;
if (ISECHO) {
if (c < 0x20) {
putq(&tp->t_oq, '^');
c += 0x40;
}
putq(&tp->t_oq, c);
putq(&tp->t_oq, '\n');
ttstart(tp);
}
goto ttin_ret;
}
}
if (ISBBYB) {
putq(&tp->t_iq, c);
if ((tp->t_flags&T_INPUT) != 0) {
s = sphi();
tp->t_flags &= ~T_INPUT;
spl(s);
defer(wakeup, (char *) &tp->t_iq);
}
if (tp->t_ipolls.e_procp) {
tp->t_ipolls.e_procp = 0;
defer(pollwake, (char *) &tp->t_ipolls);
}
} else {
if (tp->t_ibx == 0)
tp->t_opos = tp->t_hpos;
if (c == ESC)
++tp->t_escape;
else
ttstash(tp, c);
}
if (ISECHO) {
if (ISRIN || !ISEOF) {
putq(&tp->t_oq, c);
ttstart(tp);
}
}
if ((n=tp->t_iq.cq_cc)>=IHILIM) {
s = sphi();
tp->t_flags |= T_ISTOP;
spl(s);
} else if (ISTAND && (tp->t_flags&T_TSTOP)==0 && n>=ITSLIM) {
s = sphi();
tp->t_flags |= T_TSTOP;
spl(s);
putq(&tp->t_oq, stopc);
ttstart(tp);
}
ttin_ret:
return;
}
/*
* ttstash()
*
* Cooked mode.
* Put character in the buffer and check for end of line.
* Only a legal end of line can take the last character position.
*
* Only called from ttin(), and ttin() is called at high priority.
*/
static void ttstash(tp, c)
register TTY *tp;
{
register char *p1, *p2;
if (c=='\n' || ISEOF || ISBRK) {
p1 = &tp->t_ib[0];
p2 = &tp->t_ib[tp->t_ibx];
*p2++ = c; /* Always room */
while (p1 < p2)
#if NOT_8_BIT
putq(&tp->t_iq, (*p1++)&0177);
#else
putq(&tp->t_iq, (*p1++));
#endif
tp->t_ibx = 0;
tp->t_escape = 0;
if (tp->t_flags & T_INPUT) {
tp->t_flags &= ~T_INPUT;
defer(wakeup, (char *) &tp->t_iq);
}
if (tp->t_ipolls.e_procp) {
tp->t_ipolls.e_procp = 0;
defer(pollwake, (char *) &tp->t_ipolls);
}
} else if (tp->t_ibx < NCIB-1)
tp->t_ib[tp->t_ibx++] = c;
}
/*
* ttstart()
*
* Start output on a tty.
* Duck out if stopped. Do wakeups.
*/
void ttstart(tp)
register TTY *tp;
{
register int n;
int s;
n = tp->t_flags;
if (n & T_STOP)
goto stdone;
if ((n&T_DRAIN)!=0 && tp->t_oq.cq_cc==0
&& (n&T_INL)==0 && tp->t_nfill==0) {
s = sphi();
tp->t_flags &= ~T_DRAIN;
spl(s);
defer(wakeup, (char *) &tp->t_oq);
goto stdone;
}
NEAR_OR_FAR_CALL(t_start)
if (tp->t_oq.cq_cc > OLOLIM)
goto stdone;
if (n & T_HILIM) {
s = sphi();
tp->t_flags &= ~T_HILIM;
spl(s);
defer(wakeup, (char *) &tp->t_oq);
}
if (tp->t_opolls.e_procp) {
tp->t_opolls.e_procp = 0;
defer(pollwake, (char *) &tp->t_opolls);
}
stdone:
return;
}
/*
* ttflush()
*
* Flush a tty.
* Called to clear out queues.
*/
void ttflush(tp)
register TTY *tp;
{
int s;
clrq(&tp->t_iq);
clrq(&tp->t_oq);
if (tp->t_flags & T_INPUT)
defer(wakeup, (char *) &tp->t_iq);
if (tp->t_flags & (T_DRAIN|T_HILIM))
defer(wakeup, (char *) &tp->t_oq);
if (tp->t_ipolls.e_procp != 0) {
tp->t_ipolls.e_procp = 0;
defer(pollwake, (char *) &tp->t_ipolls);
}
if (tp->t_opolls.e_procp != 0) {
tp->t_opolls.e_procp = 0;
defer(pollwake, (char *) &tp->t_opolls);
}
tp->t_ibx = 0;
tp->t_escape = 0;
s = sphi();
tp->t_flags &= T_SAVE; /* reset most flag bits */
spl(s);
}
/*
* ttsignal()
*
* Send a signal to every process in the given process group.
*/
void ttsignal(tp, sig)
TTY *tp;
int sig;
{
register int g;
register PROC *pp;
g = tp->t_group;
#if DEBUG
printf("ttsignal sig=%d gp=%d\n", sig, g);
#endif
if (g == 0)
goto sigdone;
ttflush(tp);
pp = &procq;
while ((pp=pp->p_nforw) != &procq)
if (pp->p_group == g) {
sendsig(sig, pp);
}
sigdone:
return;
}
/*
* tthup()
*
* Flag hangup internally to force errors on tty read/write, flush tty,
* then send hangup signal.
*/
void tthup(tp)
register TTY *tp;
{
ttflush(tp);
ttsignal(tp, SIGHUP);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.