|
|
1.1 root 1: /*
2: * File: $USRSRC/ttydrv/tty.c
3: *
4: * Purpose: COHERENT line discipline module.
5: * This is the common part of typewriter service. It handles all device-
6: * independent aspects of a typewriter, including tandem flow control,
7: * erase and kill, stop and start, and common ioctl functions.
8: *
9: */
10:
11: /*
12: * About STOP flag bits:
13: * T_ISTOP is set when the tty module's input queue is in danger of
14: * overflow. It is up to the device driver to check this flag
15: * and do something about it. If ttin() is called with a
16: * character from the device while T_ISTOP is set, the character
17: * is discarded. T_ISTOP is cleared when the input queue is
18: * sufficiently empty. The device driver can monitor this bit for
19: * hardware flow control.
20: * T_TSTOP is the "Tandem" flow control flag for input. If TANDEM is set
21: * and the input queue is in danger of overflow, t_stopc is sent
22: * and T_TSTOP is set. When the input queue is empty enough,
23: * t_startc is sent and T_TSTOP is cleared.
24: * T_STOP is the flow control bit for output. No output will be
25: * written to the output queue while this bit is true.
26: * Except for initialization of flags in the TTY struct, by
27: * ttopen(), this bit is not written by tty.c.
28: * 91/09/15 - hal
29: */
30: /*
31: * About VMIN and VTIME:
32: * These parameters only apply when ICANON is zero.
33: * If VMIN > 0 and VTIME = 0, block until VMIN characters are received.
34: * If VMIN > 0 and VTIME > 0, block until the first character is received,
35: * then return after VMIN characters are received or VTIME/10 seconds
36: * have elapsed since last character, whichever comes first.
37: * If VMIN = 0, return after first character or after VTIME/10 seconds.
38: * (may return with read count of zero - but will return one character
39: * if it is available, even if VTIME is zero).
40: */
41:
42: /*
43: * Includes.
44: */
45: #include <kernel/v_types.h>
46:
47: #include <sys/coherent.h>
48: #include <sys/clist.h>
49: #include <sys/con.h>
50: #include <sys/deftty.h>
51: #include <sys/io.h>
52: #include <sys/proc.h>
53: #include <sys/sched.h>
54: #include <sys/stat.h>
55: #include <sys/tty.h>
56: #include <sys/errno.h>
57: #ifdef _I386
58: #include <termio.h>
59: #include <sys/file.h>
60: #else
61: #define kucopyS(k, u, n) kucopy(k, u, n)
62: #define ukcopyS(u, k, n) ukcopy(u, k, n)
63: #endif
64:
65: #ifdef TRACER
66: #define DUMPSGTTY(sp) dumpsgtty(sp)
67:
68: static void dumpsgtty(sp)
69: struct sgttyb * sp;
70: {
71: T_HAL(2, printf("S:%x:%x ", sp->sg_ispeed, sp->sg_flags));
72: }
73: #else
74: #define DUMPSGTTY(sp)
75: #endif
76:
77: /*
78: * Definitions.
79: * Constants.
80: * Macros with argument lists.
81: * Typedefs.
82: * Enums.
83: */
84:
85: #define SGTTY_CPY_LEN (sizeof (struct sgttyb))
86:
87: /* NEAR_OR_FAR_CALL is for invoking t_param and t_start */
88: #ifdef _I386
89: #define NEAR_OR_FAR_CALL(tp_fn) { (*tp->tp_fn)(tp); }
90: #define SET_HPCL { \
91: if (tp->t_termio.c_cflag & HUPCL) \
92: tp->t_flags |= T_HPCL; \
93: else \
94: tp->t_flags &= ~T_HPCL; }
95: #else
96: #define NEAR_OR_FAR_CALL(tp_fn) {\
97: if (tp->t_cs_sel) \
98: ld_call(tp->t_cs_sel, tp->tp_fn, tp); \
99: else \
100: (*tp->tp_fn)(tp); }
101: #define SET_HPCL
102: #endif
103:
104: /*
105: * Functions.
106: * Import Functions.
107: * Export Functions.
108: * Local Functions.
109: */
110: void ttclose();
111: void ttflush();
112: void tthup();
113: void ttin();
114: void ttinflush();
115: int ttinp();
116: void ttioctl();
117: void ttopen();
118: int ttout();
119: void ttoutflush();
120: int ttoutp();
121: int ttpoll();
122: void ttread();
123: void ttread0();
124: void ttsetgrp();
125: void ttsignal();
126: void ttstart();
127: void ttwrite();
128: void ttwrite0();
129:
130: static void ttstash();
131: static void ttrtp();
132:
133: #ifdef _I386
134: static void make_termio();
135: static void make_sg();
136: #else
137: #define make_termio(a1,a2,a3)
138: #define make_sg(a1,a2,a3)
139: #endif
140:
141: /*
142: * Global Data.
143: * Import Variables.
144: * Export Variables.
145: * Local Variables.
146: */
147: extern int wakeup();
148: extern void pollwake();
149:
150: /*
151: * ttopen()
152: *
153: * Called by driver on first open.
154: * Set up defaults.
155: */
156: void
157: ttopen(tp)
158: register TTY *tp;
159: {
160: tp->t_escape = 0;
161: tp->t_sgttyb.sg_ispeed = tp->t_dispeed;
162: tp->t_sgttyb.sg_ospeed = tp->t_dospeed;
163: tp->t_sgttyb.sg_erase = DEF_SG_ERASE;
164: tp->t_sgttyb.sg_kill = DEF_SG_KILL;
165: tp->t_sgttyb.sg_flags = DEF_SG_FLAGS;
166: tp->t_tchars.t_intrc = DEF_T_INTRC;
167: tp->t_tchars.t_quitc = DEF_T_QUITC;
168: tp->t_tchars.t_startc = DEF_T_STARTC;
169: tp->t_tchars.t_stopc = DEF_T_STOPC;
170: tp->t_tchars.t_eofc = DEF_T_EOFC;
171: tp->t_tchars.t_brkc = DEF_T_BRKC;
172:
173: #ifdef _I386
174: tp->t_termio.c_lflag |= ICANON;
175: tp->t_termio.c_cc[VEOL] = '\n';
176: tp->t_termio.c_cc[VEOF] = __CTRL ('D');
177: make_termio(&tp->t_sgttyb, &tp->t_tchars, &tp->t_termio);
178: if (tp->t_flags & T_HPCL)
179: tp->t_termio.c_cflag |= HUPCL;
180: else
181: tp->t_termio.c_cflag &= ~HUPCL;
182: tp->t_termio.c_cflag |= (CS8|CREAD);
183: #endif
184:
185: if (tp->t_param)
186: NEAR_OR_FAR_CALL(t_param)
187: }
188:
189: /*
190: * ttsetgrp()
191: *
192: * If process is a group leader without a control terminal,
193: * make its control terminal this device.
194: *
195: * If process is a group leader and this device does not have
196: * a process group, give it the group of the current process.
197: */
198: void ttsetgrp(tp, ctdev, mode)
199: register TTY *tp;
200: dev_t ctdev;
201: int mode;
202: {
203: register PROC *pp;
204:
205: pp = SELF;
206: #ifdef _I386
207: if (pp->p_group == pp->p_pid && 0 == (mode & IPNOCTTY)) {
208: #else
209: if (pp->p_group == pp->p_pid) {
210: #endif
211: if (pp->p_ttdev == NODEV)
212: pp->p_ttdev = ctdev;
213: if (tp->t_group == 0)
214: tp->t_group = pp->p_pid;
215: }
216: }
217:
218: /*
219: * ttyclose()
220: *
221: * Called by driver on the last close.
222: * Wait for all pending output to go out.
223: * Kill input.
224: */
225: void ttclose(tp)
226: register TTY *tp;
227: {
228: register int s;
229:
230: while (tp->t_oq.cq_cc) {
231: s = sphi();
232: if (tp->t_oq.cq_cc) {
233: tp->t_flags |= T_DRAIN;
234: /* The line discipline is waiting for the tty to drain. */
235: #ifdef _I386
236: if (x_sleep ((char *) & tp->t_oq, pritty,
237: slpriSigCatch, "ttydrain")
238: == PROCESS_SIGNALLED) {
239: #else
240: v_sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT,
241: "ttydrain");
242: if (nondsig ()) {
243: #endif
244: spl (s);
245: break;
246: }
247: }
248: spl(s);
249: }
250: ttflush(tp);
251: tp->t_flags = tp->t_group = 0;
252: }
253:
254: /*
255: * ttread()
256: *
257: * The read routine for a tty device driver will call this function.
258: *
259: * Move data from tp->t_iq to io segment iop.
260: * Number of characters to copy is in iop->ioc.
261: *
262: * In cooked mode, copy up to the first newline or break character, or
263: * until the count runs out.
264: * In CBREAK or RAW modes, return when count runs out or when input clist
265: * is empty and we're returning at least one byte.
266: */
267:
268: void ttread(tp, iop)
269: register TTY *tp;
270: register IO *iop;
271: {
272: ttread0(tp, iop, 0, 0, 0, 0);
273: }
274:
275: /* VTIME value is in 10ths of a second */
276: /* VTICKS is number of cpu ticks per VTIME unit */
277: #define VTICKS (HZ/10)
278:
279: /*
280: * ttread0()
281: *
282: * Move data from user (in IO struct) to clists.
283: * Do wakeups on functions supplied when read is blocked or completed.
284: */
285: void ttread0(tp, iop, func1, arg1, func2, arg2)
286: register TTY *tp;
287: register IO *iop;
288: int (*func1)(), arg1, (*func2)(), arg2;
289: {
290: register int c;
291: int sioc = iop->io_ioc; /* number of bytes to read */
292: #ifdef _I386
293: int time0 = lbolt;
294: int timing = 0; /* a boolean flag */
295: int got_ch = 0; /* a boolean flag */
296: unsigned char vtime = tp->t_termio.c_cc[VTIME];
297: unsigned char vmin = tp->t_termio.c_cc[VMIN];
298: #endif
299:
300: while (iop->io_ioc) {
301: pl_t prev_pl;
302: #ifdef _I386
303: /*
304: * Start VTIME timer if we got a character or vmin is zero.
305: */
306: if (! _IS_CANON_MODE (tp) && vtime) {
307: if (got_ch || vmin == 0) {
308: timing = 1;
309: time0 = lbolt;
310: timeout(&tp->t_vtime, vtime*VTICKS, wakeup,
311: &tp->t_iq);
312: }
313: }
314: #endif
315:
316: prev_pl = sphi();
317: while ((c = cltgetq (& tp->t_iq)) < 0) {
318: if ((tp->t_flags & T_CARR) == 0) {
319: u.u_error = EIO; /* error since no carrier */
320: spl (prev_pl);
321: goto read_done;
322: }
323:
324: #ifdef _I386
325: /*
326: * [T_BRD handling in COH 286 is replaced by
327: * VMIN/VTIME handling in COH 386.]
328: *
329: * If vmin is nonzero, and at least vmin characters
330: * have been received, return.
331: *
332: * If vmin is zero and vtime is zero, return
333: * whether characters have been received or not.
334: *
335: * If vmin is zero, and we got a char, return.
336: *
337: * If vtime is nonzero, and vtime 10th seconds have
338: * elapsed, return.
339: *
340: * Otherwise, go to sleep until more input arrives.
341: */
342: if (! _IS_CANON_MODE (tp)) {
343: if (vmin) {
344: /* received vmin or more characters? */
345: if ((sioc - iop->io_ioc) >= vmin) {
346: spl (prev_pl);
347: goto read_done;
348: }
349: } else {
350: if (got_ch || vtime == 0) {
351: spl (prev_pl);
352: goto read_done;
353: }
354: }
355: }
356: if (timing && ((lbolt - time0)/VTICKS) >= vtime) {
357: spl (prev_pl);
358: goto read_done;
359: }
360: #else
361: /* If we're in CBREAK or RAW mode, and we don't */
362: /* have the special "blocking read" bit set for */
363: /* these modes, and we read at least one byte */
364: /* of input, return immediately, since we have */
365: /* run out of characters from the clist. */
366:
367: if (! _IS_CANON_MODE (tp) &&
368: (tp->t_flags & T_BRD) == 0 &&
369: iop->io_ioc < sioc) {
370: spl (prev_pl);
371: goto read_done;
372: }
373: #endif
374: /*
375: * Non-blocking reads.
376: * Tell user process to try again later.
377: * How do we tell if we are a terminal or not? Check
378: * to see if we have a process group, for now.
379: */
380: if (iop->io_flag & (IONDLY | IONONBLOCK)) {
381: if (tp->t_group == 0 ||
382: (iop->io_flag & IONONBLOCK) != 0)
383: u.u_error = EAGAIN;
384: spl (prev_pl);
385: goto read_done;
386: }
387:
388: tp->t_flags |= T_INPUT; /* wait for more data */
389: if (func1)
390: (*func1)(arg1);
391: if (func2)
392: (*func2)(arg2);
393: /* The line discipline is waiting for more data. */
394: #ifdef _I386
395: if (x_sleep ((char *) & tp->t_iq, pritty,
396: slpriSigLjmp, "ttywait")
397: == PROCESS_SIGNALLED) {
398: #else
399: v_sleep((char *)&tp->t_iq, CVTTIN, IVTTIN, SVTTIN,
400: "ttywait");
401: if (nondsig ()) {
402: #endif
403: if (iop->io_ioc == sioc)
404: u.u_error = EINTR;
405: spl (prev_pl);
406: goto read_done;
407: }
408: }
409:
410: /* Got a character "c" from the input queue. */
411: got_ch = 1;
412:
413: /*
414: * Flow control - can we turn on input from the driver yet?
415: */
416: if (tp->t_iq.cq_cc <= ILOLIM) {
417: if (tp->t_flags & T_ISTOP)
418: tp->t_flags &= ~ T_ISTOP;
419: if (_IS_TANDEM_MODE (tp) &&
420: (tp->t_flags & T_TSTOP) != 0) {
421: tp->t_flags &= ~ T_TSTOP;
422: while (cltputq (& tp->t_oq,
423: tp->t_tchars.t_startc) < 0) {
424: ttstart (tp);
425: waitq ();
426: }
427: ttstart (tp);
428: }
429: }
430: spl (prev_pl);
431: if (_IS_CANON_MODE (tp) && _IS_EOF_CHAR (tp, c))
432: goto read_done;
433: if (ioputc (c, iop) < 0)
434: goto read_done;
435: if (_IS_CANON_MODE (tp) &&
436: (c == '\n' || _IS_BREAK_CHAR (tp, c)))
437: goto read_done;
438: #ifdef _I386
439: if (! _IS_CANON_MODE (tp) && vtime)
440: timing = 1;
441: #endif
442: }
443:
444: read_done:
445:
446: #ifdef _I386
447: if (timing) /* turn off the VTIME timer */
448: timeout(&tp->t_vtime, 0, 0, 0);
449: #endif
450:
451: if (func1)
452: (*func1)(arg1);
453: if (func2)
454: (*func2)(arg2);
455: return;
456: }
457:
458: /*
459: * ttwrite()
460: *
461: * Write routine.
462: */
463: void
464: ttwrite(tp, iop)
465: register TTY *tp;
466: register IO *iop;
467: {
468: ttwrite0(tp, iop, 0, 0, 0, 0);
469: }
470:
471: /*
472: * ttwrite0()
473: *
474: * Move data from user (in IO struct) to clists.
475: * Do wakeups on functions supplied when write is blocked or completed.
476: */
477: void
478: ttwrite0(tp, iop, func1, arg1, func2, arg2)
479: register TTY *tp;
480: register IO *iop;
481: int (*func1)(), arg1, (*func2)(), arg2;
482: {
483: register int c;
484:
485: /*
486: * Non-blocking writes which can fit.
487: * NOTE: exhaustion of clists can still cause blocking writes.
488: */
489: if ((iop->io_flag & (IONDLY | IONONBLOCK)) &&
490: (OHILIM >= iop->io_ioc)) {
491:
492: /*
493: * No room.
494: */
495: if (tp->t_oq.cq_cc >= OHILIM-iop->io_ioc) {
496: u.u_error = EAGAIN;
497: return;
498: }
499: }
500:
501: while ((c = iogetc(iop)) >= 0) {
502: pl_t prev_pl;
503:
504: if ((tp->t_flags & T_CARR) == 0) {
505: u.u_error = EIO; /* error since no carrier */
506: return;
507: }
508:
509: prev_pl = sphi();
510:
511: while (tp->t_oq.cq_cc >= OHILIM) {
512: ttstart (tp);
513: if (tp->t_oq.cq_cc < OHILIM)
514: break;
515: tp->t_flags |= T_HILIM;
516: if (func1)
517: (*func1)(arg1);
518: if (func2)
519: (*func2)(arg2);
520: /*
521: * The line discipline is waiting for an output
522: * queue to drain.
523: */
524: #ifdef _I386
525: if (x_sleep ((char *) & tp->t_oq, pritty,
526: slpriSigCatch, "ttyoq")
527: == PROCESS_SIGNALLED) {
528: #else
529: v_sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT,
530: "ttyoq");
531: if (nondsig ()) {
532: #endif
533: u.u_error = EINTR;
534: spl (prev_pl);
535: return;
536: }
537: }
538: while (cltputq (& tp->t_oq, c) < 0) {
539: ttstart (tp);
540: waitq ();
541: }
542: spl (prev_pl);
543: }
544:
545: ttstart (tp);
546:
547: if (func1)
548: (*func1)(arg1);
549: if (func2)
550: (*func2)(arg2);
551: }
552:
553: /*
554: * ttioctl()
555: *
556: * This routine handles common typewriter ioctl functions.
557: * Note that flushing the stream now means drain the output
558: * and clear the input.
559: */
560: void
561: ttioctl(tp, com, vec)
562: register TTY *tp;
563: int com;
564: register struct sgttyb *vec;
565: {
566: register int outDrain = 0;
567: int rload = 0;
568: int was_bbyb;
569: int inFlush = 0, outFlush = 0;
570: pl_t prev_pl;
571:
572: /*
573: * Keep sgttyb, t_chars, AND termio structs for each tty device.
574: *
575: * TCSET* writes a new termio and converts so as to update
576: * sgttyb and t_chars as well.
577: *
578: * TIOCSET[NP] writes new sgttyb and converts so as to update termio.
579: *
580: * TIOCSETC writes new t_chars and converts so as to update termio.
581: */
582: switch (com) {
583: #if _I386
584: case TCGETA:
585: if (! kucopyS (& tp->t_termio, vec, sizeof (struct termio)))
586: return;
587: break;
588:
589: case TCSETA:
590: was_bbyb = ! _IS_CANON_MODE (tp); /* previous mode */
591: if (! ukcopyS (vec, & tp->t_termio, sizeof (struct termio)))
592: return;
593: make_sg (vec, & tp->t_sgttyb, & tp->t_tchars);
594: SET_HPCL;
595: ++ rload;
596: if (! was_bbyb && ! _IS_CANON_MODE (tp))
597: ttrtp (tp);
598: break;
599:
600: case TCSETAW:
601: was_bbyb = ! _IS_CANON_MODE (tp); /* previous mode */
602: if (! ukcopyS (vec, & tp->t_termio, sizeof (struct termio)))
603: return;
604: make_sg (vec, & tp->t_sgttyb, & tp->t_tchars);
605: SET_HPCL;
606: ++ outDrain; /* delay for output */
607: ++ rload;
608: if (! was_bbyb && ! _IS_CANON_MODE (tp))
609: ttrtp (tp);
610: break;
611:
612: case TCSETAF:
613: if (! ukcopyS (vec, & tp->t_termio, sizeof (struct termio)))
614: return;
615: make_sg (vec, & tp->t_sgttyb, & tp->t_tchars);
616: SET_HPCL;
617: ++ inFlush; /* flush input */
618: ++ outDrain; /* delay for output */
619: ++ rload;
620: break;
621: #endif
622:
623: case TIOCQUERY:
624: kucopyS (& tp->t_iq.cq_cc, vec, sizeof (int));
625: break;
626:
627: case TIOCGETP:
628: /*
629: * The addressability checking for this is carried out at
630: * a higher level in order to support i286 Coherent binaries.
631: */
632: kucopy (& tp->t_sgttyb, vec, SGTTY_CPY_LEN);
633: break;
634:
635: case TIOCSETP:
636: DUMPSGTTY (& tp->t_sgttyb);
637: ++ inFlush; /* flush input */
638: ++ outDrain; /* delay for output */
639: ++ rload;
640:
641: /*
642: * The addressability checking for this is carried out at
643: * a higher level in order to support i286 Coherent binaries.
644: */
645:
646: ukcopy (vec, & tp->t_sgttyb, SGTTY_CPY_LEN);
647: make_termio (& tp->t_sgttyb, & tp->t_tchars, & tp->t_termio);
648: break;
649:
650: case TIOCSETN:
651: was_bbyb = ! _IS_CANON_MODE (tp); /* previous mode */
652: DUMPSGTTY (& tp->t_sgttyb);
653: ++ rload;
654:
655: /*
656: * The addressability checking for this is carried out at
657: * a higher level in order to support i286 Coherent binaries.
658: */
659:
660: ukcopy(vec, & tp->t_sgttyb, SGTTY_CPY_LEN);
661: make_termio (& tp->t_sgttyb, & tp->t_tchars, & tp->t_termio);
662:
663: if (! was_bbyb && ! _IS_CANON_MODE (tp))
664: ttrtp (tp);
665: break;
666:
667: case TIOCGETC:
668: kucopyS (& tp->t_tchars, vec, sizeof (struct tchars));
669: break;
670:
671: case TIOCSETC:
672: ++ rload;
673: ++ outDrain;
674: if (! ukcopyS (vec, & tp->t_tchars, sizeof (struct tchars)))
675: return;
676: make_termio (& tp->t_sgttyb, & tp->t_tchars, & tp->t_termio);
677: break;
678:
679: case TIOCEXCL:
680: prev_pl = sphi ();
681: tp->t_flags |= T_EXCL;
682: spl (prev_pl);
683: break;
684:
685: case TIOCNXCL:
686: prev_pl = sphi ();
687: tp->t_flags &= ~T_EXCL;
688: spl (prev_pl);
689: break;
690:
691: case TIOCHPCL: /* set hangup on last close */
692: prev_pl = sphi ();
693: tp->t_flags |= T_HPCL;
694: spl (prev_pl);
695: #ifdef _I386
696: tp->t_termio.c_cflag |= HUPCL;
697: #endif
698: break;
699:
700: case TIOCCHPCL: /* don't hangup on last close */
701: if (! super ()) /* only superuser may do this */
702: u.u_error = EPERM; /* not su */
703: else {
704: prev_pl = sphi ();
705: tp->t_flags &= ~T_HPCL; /* turn off hangup bit */
706: spl (prev_pl);
707: #ifdef _I386
708: tp->t_termio.c_cflag &= ~HUPCL;
709: #endif
710: }
711: break;
712:
713: case TIOCGETTF: /* get tty flag word */
714: kucopyS (& tp->t_flags, (unsigned *) vec, sizeof (unsigned));
715: break;
716:
717: #ifdef _I386
718: case TCFLSH:
719: switch ((int) vec) {
720: case 0: inFlush ++; break;
721: case 1: outFlush ++; break;
722: case 2: inFlush ++; outFlush ++; break;
723: default: u.u_error = EINVAL;
724: }
725: break;
726:
727: case TCSBRK:
728: ++ outDrain;
729: break;
730:
731: #endif
732: case TIOCFLUSH:
733: ++ inFlush; /* flush both input and output */
734: ++ outFlush;
735: /* ++ outDrain; Why? - hws - 91/11/22 */
736: break;
737:
738: #ifndef _I386
739: case TIOCBREAD: /* blocking read for CBREAK/RAW mode */
740: prev_pl = sphi ();
741: tp->t_flags |= T_BRD;
742: spl (prev_pl);
743: break;
744:
745: case TIOCCBREAD: /* turn off CBREAK/RAW blocking read mode */
746: prev_pl = sphi ();
747: tp->t_flags &= ~ T_BRD;
748: spl (prev_pl);
749: break;
750: #endif
751: /*
752: * The following is a hack so that the process group for /dev/console
753: * contains the current login shell running on it.
754: * Only expect /etc/init to use this ugliness.
755: */
756: case TIOCSETG:
757: if (super ())
758: tp->t_group = SELF->p_group;
759: break;
760: default:
761: u.u_error = EINVAL;
762: }
763:
764: /*
765: * T_STOP is set under two conditions:
766: * - a modem control device is awaiting carrier
767: * - a stopc (usually Ctrl-S) character was received.
768: *
769: * If ioctl just put device into RAWIN mode, make sure device
770: * is not still waiting for startc.
771: */
772: #if _I386
773: /* Is XON/XOFF flow control off *and* we are waiting for startc? */
774: if (! _IS_IXON_MODE (tp) && (tp->t_flags & T_XSTOP) != 0) {
775: prev_pl = sphi ();
776: tp->t_flags &= ~ (T_STOP | T_XSTOP);
777: spl (prev_pl);
778:
779: ttstart (tp);
780: }
781: #else
782: if (! _IS_IXON_MODE (tp)) && (tp->t_flags & T_STOP) != 0 &&
783: (tp->t_flags & T_HOPEN) == 0) {
784: prev_pl = sphi ();
785: tp->t_flags &= ~ T_STOP;
786: spl (prev_pl);
787:
788: ttstart (tp);
789: }
790: #endif
791:
792: /*
793: * Wait for output to drain, or signal to arrive.
794: *
795: * NOTE: This stuff is properly done within the device driver,
796: * *before* ttioctl() is called. This paragraph should disappear
797: * from tty.c, with maybe an entry point added for the driver to
798: * drain the queue while draining the peripheral device. -hws-
799: */
800:
801: if (outDrain) {
802: while (tp->t_oq.cq_cc) {
803: prev_pl = sphi ();
804: tp->t_flags |= T_DRAIN;
805: spl (prev_pl);
806: /* A TIOC has asked for tty output to drain. */
807: #ifdef _I386
808: if (x_sleep ((char *) & tp->t_oq, pritty,
809: slpriSigCatch, "ttyiodrn")
810: == PROCESS_SIGNALLED) {
811: #else
812: v_sleep((char *)&tp->t_oq, CVTTOUT, IVTTOUT, SVTTOUT,
813: "ttyiodrn");
814: if (nondsig ()) {
815: #endif
816: break;
817: }
818: }
819: }
820:
821: /*
822: * Flush.
823: */
824: if (inFlush)
825: ttinflush(tp);
826: if (outFlush)
827: ttoutflush(tp);
828:
829: /*
830: * Re-initialize hardware.
831: */
832: if (rload) {
833: if (tp->t_param)
834: NEAR_OR_FAR_CALL(t_param)
835: }
836: }
837:
838: /*
839: * ttpoll()
840: *
841: * Polling routine.
842: * [System V.3 Compatible]
843: */
844: int ttpoll(tp, ev, msec)
845: register TTY * tp;
846: int ev;
847: int msec;
848: {
849: /*
850: * Priority polls not supported.
851: */
852: ev &= ~POLLPRI;
853:
854: /*
855: * Input poll with no data present.
856: */
857: if ((ev & POLLIN) && (tp->t_iq.cq_cc == 0)) {
858:
859: /*
860: * Blocking input poll.
861: */
862: if (msec)
863: pollopen(&tp->t_ipolls);
864:
865: /*
866: * Second look to avoid interrupt race.
867: */
868: if (tp->t_iq.cq_cc == 0)
869: ev &= ~POLLIN;
870: }
871:
872: /*
873: * Output poll with no space.
874: */
875: if ((ev & POLLOUT) && (tp->t_oq.cq_cc >= OLOLIM)) {
876:
877: /*
878: * Blocking output poll.
879: */
880: if (msec)
881: pollopen(&tp->t_opolls);
882:
883: /*
884: * Second look to avoid interrupt race.
885: */
886: if (tp->t_oq.cq_cc >= OLOLIM)
887: ev &= ~POLLOUT;
888: }
889:
890: if (((ev & POLLIN) == 0) && ((tp->t_flags & T_CARR) == 0))
891: ev |= POLLHUP;
892:
893: return ev;
894: }
895:
896: /*
897: * ttout()
898: *
899: * Pull a character from the output queues of the typewriter.
900: * Doing fills, newline insert, tab expansion, etc.
901: *
902: * If the stream is empty return a -1.
903: * Called at high priority.
904: */
905: int ttout(tp)
906: register TTY *tp;
907: {
908: register int c;
909:
910: if (tp->t_nfill) {
911: --tp->t_nfill;
912: c = tp->t_fillb;
913: } else if (tp->t_flags & T_INL) {
914: tp->t_flags &= ~T_INL;
915: c = '\n';
916: } else {
917: if ((c=cltgetq(&tp->t_oq)) < 0)
918: return -1;
919: if (! _IS_RAW_OUT_MODE (tp)) {
920: if (c == '\n' && _IS_ONLCR_MODE (tp)) {
921: tp->t_flags |= T_INL;
922: c = '\r';
923: } else if (c == '\r' && _IS_OCRNL_MODE (tp)) {
924: c = '\n';
925: } else if (c == '\t' && _IS_XTABS_MODE (tp)) {
926: tp->t_nfill = ~ (tp->t_hpos | ~ 7);
927: tp->t_fillb = ' ';
928: c = ' ';
929: }
930: }
931: }
932: if (! _IS_RAW_OUT_MODE (tp)) {
933: if (c == '\b') {
934: if (tp->t_hpos)
935: -- tp->t_hpos;
936: } else if (c == '\r')
937: tp->t_hpos = 0;
938: else if (c == '\t')
939: tp->t_hpos = (tp->t_hpos | 7) + 1;
940: #if NOT_8_BIT
941: else if (c >= ' ' && c <= '~')
942: #else
943: else if ((c >= ' ' && c <= '~') || (c >= 0200 && c <= 0376))
944: #endif
945: ++ tp->t_hpos;
946: }
947: return c;
948: }
949:
950: /*
951: * ttin()
952: *
953: * Pass a character to the device independent typewriter routines.
954: * Handle erase and kill, tandem flow control, and other magic.
955: * Often called at high priority from the driver's interrupt routine.
956: */
957: void
958: ttin(tp, c)
959: register TTY *tp;
960: register int c;
961: {
962: int dc, i, n;
963: pl_t prev_pl;
964:
965: if (_IS_ISTRIP_MODE (tp))
966: c &= 0x7F;
967:
968: if (_IS_ISIG_MODE (tp) && _IS_QUIT_CHAR (tp, c)) {
969: ttsignal (tp, SIGQUIT);
970: goto ttin_ret;
971: }
972:
973: if (_IS_ISIG_MODE (tp) && _IS_INTERRUPT_CHAR (tp, c)) {
974: ttsignal (tp, SIGINT);
975: goto ttin_ret;
976: }
977:
978: if (tp->t_flags & T_ISTOP)
979: goto ttin_ret;
980:
981: if (_IS_ICRNL_MODE (tp) && ! _IS_IGNCR_MODE (tp)) {
982: if (c == '\r')
983: c = '\n';
984: }
985:
986: if (! _IS_RAW_INPUT_MODE (tp)) {
987: if (tp->t_escape) {
988: if (c == ESC)
989: ++ tp->t_escape;
990: else {
991: if (_IS_ERASE_CHAR (tp, c) ||
992: _IS_KILL_CHAR (tp, c)) {
993: c |= 0x80;
994: -- tp->t_escape;
995: }
996: while (tp->t_escape && tp->t_ibx < NCIB - 1) {
997: tp->t_ib [tp->t_ibx ++] = ESC;
998: -- tp->t_escape;
999: }
1000: ttstash (tp, c);
1001: }
1002: if (_IS_ECHO_MODE (tp)) {
1003: #if NOT_8_BIT
1004: cltputq (& tp->t_oq, c & 0x7F);
1005: #else
1006: cltputq (& tp->t_oq, c); /* no strip for 8-bit */
1007: #endif
1008: ttstart (tp);
1009: }
1010: goto ttin_ret;
1011: }
1012: if (_IS_ERASE_CHAR (tp, c) && _IS_CANON_MODE (tp)) {
1013: while (tp->t_escape && tp->t_ibx < NCIB - 1) {
1014: tp->t_ib [tp->t_ibx ++] = ESC;
1015: -- tp->t_escape;
1016: }
1017: if (tp->t_ibx == 0)
1018: goto ttin_ret;
1019: dc = tp->t_ib [-- tp->t_ibx];
1020: if (_IS_ECHO_MODE (tp)) {
1021: if (! _IS_CRT_MODE (tp))
1022: cltputq (& tp->t_oq, c);
1023: /* don't erase for bell, null, or rubout */
1024: #if NOT_8_BIT
1025: else if ((c = dc & 0x7F) == '\a' || c == 0 ||
1026: c == 0x7F)
1027: #else
1028: else if ((c = dc) == '\a' || c == 0 ||
1029: c == 0x7F || c == 0xFF)
1030: #endif
1031: goto ttin_ret;
1032: else if (c != '\b' && c != '\t') {
1033: cltputq (& tp->t_oq, '\b');
1034: cltputq (& tp->t_oq, ' ');
1035: cltputq (& tp->t_oq, '\b');
1036: } else if (c == '\t') {
1037: n = tp->t_opos + tp->t_escape;
1038: for (i = 0 ; i < tp->t_ibx ; ++ i) {
1039: c = tp->t_ib [i];
1040: #if NOT_8_BIT
1041: if (c & 0x80) {
1042: ++ n;
1043: c &= 0x7F;
1044: }
1045: #endif
1046: if (c == '\b')
1047: -- n;
1048: else {
1049: if (c == '\t')
1050: n |= 07;
1051: ++ n;
1052: }
1053: }
1054: while (n ++ < tp->t_hpos)
1055: cltputq (& tp->t_oq, '\b');
1056: }
1057: #if NOT_8_BIT
1058: if (dc & 0x80) {
1059: if ((dc & 0x7F) != '\b')
1060: cltputq (& tp->t_oq, '\b');
1061: cltputq (& tp->t_oq, ' ');
1062: cltputq (& tp->t_oq, '\b');
1063: }
1064: #endif
1065: ttstart (tp);
1066: }
1067: goto ttin_ret;
1068: }
1069: if (_IS_KILL_CHAR (tp, c) && _IS_CANON_MODE (tp)) {
1070: tp->t_ibx = 0;
1071: tp->t_escape = 0;
1072: if (_IS_ECHO_MODE (tp)) {
1073: if (c < 0x20) {
1074: cltputq (& tp->t_oq, '^');
1075: c += 0x40;
1076: }
1077: cltputq (& tp->t_oq, c);
1078: cltputq (& tp->t_oq, '\n');
1079: ttstart (tp);
1080: }
1081: goto ttin_ret;
1082: }
1083: }
1084: if (! _IS_CANON_MODE (tp)) {
1085: cltputq (& tp->t_iq, c);
1086: if (tp->t_flags & T_INPUT) {
1087: prev_pl = sphi ();
1088: tp->t_flags &= ~T_INPUT;
1089: spl (prev_pl);
1090: wakeup (& tp->t_iq);
1091: }
1092: if (tp->t_ipolls.e_procp) {
1093: tp->t_ipolls.e_procp = 0;
1094: pollwake ((char *) & tp->t_ipolls);
1095: }
1096: } else {
1097: if (tp->t_ibx == 0)
1098: tp->t_opos = tp->t_hpos;
1099: if (c == ESC)
1100: ++ tp->t_escape;
1101: else
1102: ttstash(tp, c);
1103: }
1104: if (_IS_ECHO_MODE (tp)) {
1105: if (_IS_RAW_INPUT_MODE (tp) || ! _IS_EOF_CHAR (tp, c)) {
1106: cltputq (& tp->t_oq, c);
1107: ttstart (tp);
1108: }
1109: }
1110: if ((n = tp->t_iq.cq_cc) >= IHILIM) {
1111: prev_pl = sphi ();
1112: tp->t_flags |= T_ISTOP;
1113: spl (prev_pl);
1114: } else if (_IS_TANDEM_MODE (tp) && (tp->t_flags & T_TSTOP)==0 &&
1115: n >= ITSLIM) {
1116: prev_pl = sphi ();
1117: tp->t_flags |= T_TSTOP;
1118: spl (prev_pl);
1119: cltputq (& tp->t_oq, tp->t_tchars.t_stopc);
1120: ttstart (tp);
1121: }
1122:
1123: ttin_ret:
1124: return;
1125: }
1126:
1127: /*
1128: * ttstash()
1129: *
1130: * Cooked mode.
1131: * Put character in the buffer and check for end of line.
1132: * Only a legal end of line can take the last character position.
1133: *
1134: * Only called from ttin(), and ttin() is called at high priority.
1135: */
1136: static void ttstash(tp, c)
1137: register TTY *tp;
1138: {
1139: register char *p1, *p2;
1140:
1141: if (c == '\n' || _IS_EOF_CHAR (tp, c) || _IS_BREAK_CHAR (tp, c)) {
1142: p1 = & tp->t_ib [0];
1143: p2 = & tp->t_ib [tp->t_ibx];
1144: * p2 ++ = c; /* Always room */
1145: while (p1 < p2)
1146: #if NOT_8_BIT
1147: cltputq (& tp->t_iq, (* p1 ++) & 0x7F);
1148: #else
1149: cltputq (& tp->t_iq, (* p1 ++));
1150: #endif
1151: tp->t_ibx = 0;
1152: tp->t_escape = 0;
1153:
1154: if (tp->t_flags & T_INPUT) {
1155: tp->t_flags &= ~ T_INPUT;
1156: wakeup (& tp->t_iq);
1157: }
1158:
1159: if (tp->t_ipolls.e_procp) {
1160: tp->t_ipolls.e_procp = 0;
1161: pollwake ((char *) & tp->t_ipolls);
1162: }
1163:
1164: } else if (tp->t_ibx < NCIB - 1)
1165: tp->t_ib [tp->t_ibx ++] = c;
1166: }
1167:
1168: /*
1169: * ttstart()
1170: *
1171: * Start output on a tty.
1172: * Duck out if stopped. Do wakeups.
1173: */
1174: void ttstart(tp)
1175: register TTY *tp;
1176: {
1177: register int n;
1178: pl_t prev_pl;
1179:
1180: n = tp->t_flags;
1181: if (n & T_STOP)
1182: goto stdone;
1183:
1184: if ((n & T_DRAIN) != 0 && tp->t_oq.cq_cc == 0 && (n & T_INL) == 0 &&
1185: tp->t_nfill == 0) {
1186: prev_pl = sphi ();
1187: tp->t_flags &= ~ T_DRAIN;
1188: spl (prev_pl);
1189: wakeup (& tp->t_oq);
1190: goto stdone;
1191: }
1192:
1193: NEAR_OR_FAR_CALL(t_start)
1194:
1195: if (tp->t_oq.cq_cc > OLOLIM)
1196: goto stdone;
1197:
1198: if (n & T_HILIM) {
1199: prev_pl = sphi ();
1200: tp->t_flags &= ~ T_HILIM;
1201: spl (prev_pl);
1202: wakeup (& tp->t_oq);
1203: }
1204:
1205: if (tp->t_opolls.e_procp) {
1206: tp->t_opolls.e_procp = 0;
1207: pollwake ((char *) & tp->t_opolls);
1208: }
1209: stdone:
1210: return;
1211: }
1212:
1213: /*
1214: * ttflush()
1215: *
1216: * Flush tty input and output queues.
1217: */
1218: void
1219: ttflush(tp)
1220: register TTY *tp;
1221: {
1222: ttinflush (tp);
1223: ttoutflush (tp);
1224: }
1225:
1226: /*
1227: * ttinflush()
1228: *
1229: * Flush input queues.
1230: */
1231: void
1232: ttinflush(tp)
1233: register TTY *tp;
1234: {
1235: clrq (& tp->t_iq);
1236:
1237: if (tp->t_flags & T_INPUT) {
1238: wakeup (& tp->t_iq);
1239: }
1240:
1241: if (tp->t_ipolls.e_procp) {
1242: tp->t_ipolls.e_procp = 0;
1243: pollwake ((char *) & tp->t_ipolls);
1244: }
1245:
1246: tp->t_ibx = 0;
1247: tp->t_escape = 0;
1248: }
1249:
1250: /*
1251: * ttoutflush()
1252: *
1253: * Flush tty output queues.
1254: */
1255: void
1256: ttoutflush(tp)
1257: register TTY *tp;
1258: {
1259: clrq(&tp->t_oq);
1260:
1261: if (tp->t_flags & (T_DRAIN | T_HILIM)) {
1262: wakeup (& tp->t_oq);
1263: }
1264:
1265: if (tp->t_opolls.e_procp) {
1266: tp->t_opolls.e_procp = 0;
1267: pollwake ((char *) & tp->t_opolls);
1268: }
1269: }
1270:
1271: /*
1272: * ttsignal()
1273: *
1274: * Send a signal to every process in the given process group.
1275: */
1276: void
1277: ttsignal(tp, sig)
1278: TTY *tp;
1279: int sig;
1280: {
1281: register int g;
1282: register PROC *pp;
1283:
1284: g = tp->t_group;
1285: if (g == 0)
1286: goto sigdone;
1287: ttflush(tp);
1288: pp = & procq;
1289: while ((pp = pp->p_nforw) != & procq) {
1290: if (pp->p_group == g)
1291: sendsig(sig, pp);
1292: }
1293: sigdone:
1294: return;
1295: }
1296:
1297: /*
1298: * tthup()
1299: *
1300: * Flag hangup internally to force errors on tty read/write, flush tty,
1301: * then send hangup signal.
1302: */
1303: void tthup(tp)
1304: register TTY *tp;
1305: {
1306: ttflush (tp);
1307: ttsignal (tp, SIGHUP);
1308: }
1309:
1310: #if _I386
1311: /*
1312: * Convert from sgttyb and tchars structs to termio.
1313: */
1314: static void
1315: make_termio(sgp, tcp, trp)
1316: struct sgttyb * sgp;
1317: struct tchars * tcp;
1318: struct termio * trp;
1319: {
1320: char vmin = 1, vtime = 0;
1321: char veof = 4, veol = 10; /* default to ^D, ^J */
1322:
1323: /*
1324: * If VMIN/VTIME are active, save now for possible restore.
1325: */
1326: if ((trp->c_lflag & ICANON) == 0) {
1327: vmin = trp->c_cc [VMIN];
1328: vtime = trp->c_cc [VTIME];
1329: } else {
1330: veol = trp->c_cc [VEOL];
1331: }
1332:
1333: trp->c_cc [VINTR] = tcp->t_intrc;
1334: trp->c_cc [VQUIT] = tcp->t_quitc;
1335: veof = tcp->t_eofc;
1336: trp->c_cc [VERASE] = sgp->sg_erase;
1337: trp->c_cc [VKILL ] = sgp->sg_kill;
1338:
1339: trp->c_iflag = BRKINT | IXON | IGNPAR | INPCK;
1340: trp->c_oflag = OPOST;
1341: trp->c_cflag &= CSIZE | HUPCL | CLOCAL | CREAD;
1342: trp->c_lflag = ICANON | ISIG | ECHONL | ECHOK;
1343:
1344: if (sgp->sg_flags & TANDEM)
1345: trp->c_iflag |= IXOFF;
1346:
1347: if (sgp->sg_flags & CRMOD) {
1348: trp->c_iflag |= ICRNL;
1349: trp->c_oflag |= ONLCR;
1350: }
1351:
1352: if (sgp->sg_flags & LCASE) {
1353: trp->c_lflag |= XCASE;
1354: trp->c_iflag |= IUCLC;
1355: trp->c_oflag |= OLCUC;
1356: }
1357:
1358: if (sgp->sg_flags & (RAW | RAWIN)) {
1359: trp->c_iflag = 0;
1360: trp->c_cflag &= ~ (PARODD|PARENB);
1361: trp->c_cflag |= CS8 | CREAD;
1362: trp->c_lflag &= ~ (ECHONL | ISIG | ICANON);
1363: }
1364:
1365: if (sgp->sg_flags & (RAW|RAWOUT)) {
1366: trp->c_oflag &= ~ OPOST;
1367: trp->c_lflag &= ~ XCASE;
1368: }
1369:
1370: if (sgp->sg_flags & XTABS)
1371: trp->c_oflag |= TAB3;
1372:
1373: if (sgp->sg_flags & (EVENP | ODDP)) {
1374: trp->c_cflag |= PARENB;
1375: if (sgp->sg_flags & ODDP)
1376: trp->c_cflag |= PARODD;
1377: }
1378: trp->c_cflag |= sgp->sg_ispeed;
1379:
1380: if (sgp->sg_flags & CRT)
1381: trp->c_lflag |= ECHOE;
1382:
1383: if (sgp->sg_flags & CBREAK)
1384: trp->c_lflag &= ~ ICANON;
1385:
1386: if (sgp->sg_flags & ECHO)
1387: trp->c_lflag |= ECHO;
1388:
1389: /*
1390: * If not doing canonical processing, set VMIN/VTIME.
1391: */
1392:
1393: if ((trp->c_lflag & ICANON) == 0) {
1394: trp->c_cc [VMIN] = vmin;
1395: trp->c_cc [VTIME] = vtime;
1396: } else {
1397: trp->c_cc [VEOF] = veof;
1398: trp->c_cc [VEOL] = veol;
1399: }
1400: }
1401:
1402: /*
1403: * Convert from termio struct to sgttyb and tchars.
1404: */
1405: static void
1406: make_sg(trp, sgp, tcp)
1407: struct termio * trp;
1408: struct sgttyb * sgp;
1409: struct tchars * tcp;
1410: {
1411: T_HAL(1, printf("T:%x:%x:%x:%x ", trp->c_iflag, trp->c_oflag,
1412: trp->c_cflag, trp->c_lflag));
1413: tcp->t_intrc = trp->c_cc [VINTR];
1414: tcp->t_quitc = trp->c_cc [VQUIT];
1415: tcp->t_startc= __CTRL ('Q');
1416: tcp->t_stopc = __CTRL ('S');
1417: tcp->t_eofc = trp->c_cc [VEOF];
1418: tcp->t_brkc = -1;
1419:
1420: sgp->sg_erase = trp->c_cc [VERASE];
1421: sgp->sg_kill = trp->c_cc [VKILL];
1422: sgp->sg_ispeed = trp->c_cflag & CBAUD;
1423: sgp->sg_ospeed = sgp->sg_ispeed;
1424: sgp->sg_flags = RAWIN | RAWOUT | CBREAK;
1425:
1426: if (trp->c_lflag & ECHO)
1427: sgp->sg_flags |= ECHO;
1428:
1429: if (trp->c_lflag & ECHOE)
1430: sgp->sg_flags |= CRT;
1431:
1432: if ((trp->c_lflag & XCASE) != 0 || (trp->c_oflag & OLCUC) != 0 ||
1433: (trp->c_iflag & IUCLC) != 0)
1434: sgp->sg_flags |= LCASE;
1435:
1436: if (trp->c_iflag & IXOFF)
1437: sgp->sg_flags |= TANDEM;
1438:
1439: if (trp->c_iflag & ICRNL)
1440: sgp->sg_flags |= CRMOD;
1441:
1442: if (trp->c_oflag & ONLCR)
1443: sgp->sg_flags |= CRMOD;
1444:
1445: if (trp->c_oflag & OPOST)
1446: sgp->sg_flags &= ~ RAWOUT;
1447:
1448: if ((trp->c_oflag & TABDLY) == TAB3)
1449: sgp->sg_flags |= XTABS;
1450:
1451: if (trp->c_cflag & PARENB) {
1452: if (trp->c_cflag & PARODD)
1453: sgp->sg_flags |= ODDP;
1454: else
1455: sgp->sg_flags |= EVENP;
1456: }
1457:
1458: if (trp->c_lflag & ISIG)
1459: sgp->sg_flags &= ~ RAWIN;
1460:
1461: if (trp->c_lflag & ICANON)
1462: sgp->sg_flags &= ~ CBREAK;
1463: }
1464: #endif
1465:
1466: /*
1467: * ttrtp()
1468: *
1469: * Recover contents of typeahead when changing modes.
1470: * Called for ioctls of TIOCSETP and TCSETA,
1471: * when going from not byte-by-byte input to BBYB.
1472: */
1473: static void
1474: ttrtp(tp)
1475: TTY * tp;
1476: {
1477: register char *p1, *p2;
1478:
1479: if (tp->t_ibx) {
1480: p1 = & tp->t_ib [0];
1481: p2 = & tp->t_ib [tp->t_ibx];
1482: while (p1 < p2) {
1483: #if NOT_8_BIT
1484: cltputq (& tp->t_iq, (* p1 ++) & 0x7F);
1485: #else
1486: cltputq (& tp->t_iq, (* p1 ++));
1487: #endif
1488: }
1489: tp->t_ibx = 0;
1490: }
1491: }
1492:
1493: /*
1494: * ttinp()
1495: *
1496: * Return nonzero if ttin() may be called to send data for pickup by ttread(),
1497: * or 0 if not.
1498: */
1499:
1500: int
1501: ttinp(tp)
1502: TTY * tp;
1503: {
1504: return (tp->t_flags & T_ISTOP) == 0;
1505: }
1506:
1507: /*
1508: * ttoutp()
1509: *
1510: * Return nonzero if ttout() may be called to fetch data stored by ttwrite(),
1511: * or 0 if not.
1512: */
1513:
1514: int
1515: ttoutp(tp)
1516: TTY * tp;
1517: {
1518: return tp->t_nfill || (tp->t_flags & T_INL) != 0 || tp->t_oq.cq_cc;
1519: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.