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