|
|
1.1 root 1: /* pty.c 4.8 81/08/14 */
2:
3: /*
4: * Pseudo-teletype Driver
5: * (Actually two drivers, requiring two entries in 'cdevsw')
6: */
7: #include "pty.h"
8:
9: #if NPTY > 0
10:
11: #include "../h/param.h"
12: #include "../h/systm.h"
13: #include "../h/tty.h"
14: #include "../h/dir.h"
15: #include "../h/user.h"
16: #include "../h/conf.h"
17: #include "../h/buf.h"
18: #include "../h/file.h"
19:
20: #define NPTY 16 /* Number of pseudo-teletypes */
21: #define BUFSIZ 100 /* Chunk size iomoved from user */
22: #define ALLDELAYS (NLDELAY|TBDELAY|XTABS|CRDELAY|VTDELAY)
23: /*
24: * A pseudo-teletype is a special device which is not unlike a pipe.
25: * It is used to communicate between two processes. However, it allows
26: * one to simulate a teletype, including mode setting, interrupt, and
27: * multiple end of files (all not possible on a pipe). There are
28: * really two drivers here. One is the device which looks like a TTY
29: * and can be thought of as the slave device, and hence its routines
30: * are prefixed with 'pts' (PTY Slave). The other driver can be
31: * thought of as the controlling device, and its routines are prefixed
32: * by 'ptc' (PTY Controller). To type on the simulated keyboard of the
33: * PTY, one does a 'write' to the controlling device. To get the
34: * simulated printout from the PTY, one does a 'read' on the controlling
35: * device. Normally, the controlling device is called 'ptyx' and the
36: * slave device is called 'ttyx' (to make programs like 'who' happy).
37: */
38:
39: struct tty pt_tty[NPTY]; /* TTY headers for PTYs */
40:
41: /*ARGSUSED*/
42: ptsopen(dev, flag)
43: dev_t dev;
44: { /* Open for PTY Slave */
45: register struct tty *tp;
46:
47: if(minor(dev) >= NPTY) {
48: u.u_error = ENXIO;
49: return;
50: }
51: tp = &pt_tty[minor(dev)];
52: if((tp->t_state & ISOPEN) == 0) {
53: ttychars(tp); /* Set up default chars */
54: tp->t_flags = 0; /* No features (nor raw mode) */
55: } else if(tp->t_state&XCLUDE && u.u_uid != 0) {
56: u.u_error = EBUSY;
57: return;
58: }
59: if(tp->t_oproc) /* Ctrlr still around. */
60: tp->t_state |= CARR_ON;
61: while((tp->t_state & CARR_ON) == 0) {
62: tp->t_state |= WOPEN;
63: sleep((caddr_t)&tp->t_rawq, TTIPRI);
64: }
65: (*linesw[tp->t_line].l_open)(dev, tp);
66: }
67:
68: ptsclose(dev)
69: dev_t dev;
70: { /* Close slave part of PTY */
71: register struct tty *tp;
72:
73: tp = &pt_tty[minor(dev)];
74: (*linesw[tp->t_line].l_close)(tp);
75: }
76:
77: ptsread(dev)
78: dev_t dev;
79: { /* Read from PTY, i.e. from data written by controlling device */
80: register struct tty *tp;
81:
82: tp = &pt_tty[minor(dev)];
83: if(tp->t_oproc) {
84: (*linesw[tp->t_line].l_read)(tp);
85: /* Wakeup other half if sleeping */
86: wakeup((caddr_t)&tp->t_rawq.c_cf);
87: }
88: }
89:
90: ptswrite(dev)
91: dev_t dev;
92: { /* Write on PTY, i.e. to be read from
93: controlling device */
94: register struct tty *tp;
95:
96: tp = &pt_tty[minor(dev)];
97: /* Wait for controlling device to be opened */
98: if(tp->t_oproc)
99: (*linesw[tp->t_line].l_write)(tp);
100: }
101:
102: ptsstart(tp)
103: struct tty *tp;
104: { /* Called by 'ttstart' to output a character.
105: Merely wakes up controlling half, which
106: does actual work */
107: if(tp->t_state & TTSTOP)
108: return;
109: wakeup((caddr_t)&tp->t_outq.c_cf);
110: }
111:
112: /*ARGSUSED*/
113: ptcopen(dev, flag)
114: dev_t dev;
115: { /* Open for PTY Controller */
116: register struct tty *tp;
117:
118: if(minor(dev) >= NPTY) {
119: u.u_error = ENXIO;
120: return;
121: }
122: tp = &pt_tty[minor(dev)];
123: if(tp->t_oproc) {
124: u.u_error = EIO;
125: return;
126: }
127: tp->t_oproc = ptsstart; /* Set address of start routine */
128: tp->t_iproc = 0;
129: if(tp->t_state & WOPEN)
130: wakeup((caddr_t)&tp->t_rawq);
131: tp->t_state |= CARR_ON;
132: }
133:
134: ptcclose(dev)
135: dev_t dev;
136: { /* Close controlling part of PTY */
137: register struct tty *tp;
138:
139: tp = &pt_tty[minor(dev)];
140: if(tp->t_state & ISOPEN)
141: gsignal(tp->t_pgrp, SIGHUP);
142: tp->t_state &= ~CARR_ON; /* Virtual carrier is gone */
143: flushtty(tp, FREAD|FWRITE); /* Clean things up */
144: tp->t_oproc = 0; /* Mark as closed */
145: }
146:
147: ptcread(dev)
148: dev_t dev;
149: { /* Read from PTY's output buffer */
150: register struct tty *tp;
151:
152: tp = &pt_tty[minor(dev)];
153: if((tp->t_state&(CARR_ON|ISOPEN)) == 0)
154: return;
155: while(tp->t_outq.c_cc == 0 || /* Wait for something to arrive */
156: (tp->t_state&TTSTOP)) /* (Woken by ptsstart) */
157: sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
158: while(tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0);
159: if(tp->t_outq.c_cc <= TTLOWAT(tp) && (tp->t_state&ASLEEP)) {
160: tp->t_state &= ~ASLEEP;
161: if(tp->t_chan)
162: mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
163: else
164: wakeup((caddr_t)&tp->t_outq);
165: }
166: }
167:
168: ptcwrite(dev)
169: dev_t dev;
170: { /* Stuff characters into PTY's input buffer */
171: register struct tty *tp;
172: register char *cp, *ce;
173: register int cc;
174: char locbuf[BUFSIZ];
175:
176: tp = &pt_tty[minor(dev)];
177: if((tp->t_state&(CARR_ON|ISOPEN)) == 0)
178: return;
179: while(u.u_count) {
180: cc = MIN(u.u_count, BUFSIZ);
181: cp = locbuf;
182: iomove(cp, (unsigned)cc, B_WRITE);
183: if(u.u_error)
184: break;
185: ce = cp + cc;
186: while(cp < ce) {
187: while(tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
188: wakeup((caddr_t)&tp->t_rawq);
189: /* Better than just flushing it! */
190: /* Wait for something to be read */
191: sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
192: }
193: (*linesw[tp->t_line].l_rint)(*cp++, tp);
194: }
195: }
196: }
197:
198: /* Note: Both slave and controlling device have the same routine for */
199: /* 'ioctl' (but note check for controller - 4/12/78:mob)*/
200: /*ARGSUSED*/
201: ptyioctl(dev, cmd, addr, flag)
202: caddr_t addr;
203: dev_t dev;
204: { /* Read and write status bits */
205: register struct tty *tp;
206: register int tbd;
207: #ifdef BLAND
208: register int nld;
209: #endif
210:
211: tp = &pt_tty[minor(dev)];
212: /* if controller stty then must flush to prevent a hang */
213: if(cdevsw[major(dev)].d_open == ptcopen && cmd == TIOCSETP)
214: while(getc(&tp->t_outq) >= 0);
215: if(ttioctl(tp, cmd, addr, dev)) {
216: if(cmd == TIOCSETP || cmd == TIOCSETN) {
217: #ifdef BLAND
218: nld = tp->t_flags & NLDELAY;
219: #endif
220: tbd = tp->t_flags & TBDELAY;
221: tp->t_flags &= ~ALLDELAYS;
222: if(tbd == TBDELAY) /* Wants tab expansion */
223: tp->t_flags |= tbd;
224: #ifdef BLAND
225: if(nld == NLDELAY) /* Allow ANN ARBOR mode. */
226: tp->t_flags |= nld;
227: #endif
228: }
229: } else
230: u.u_error = ENOTTY;
231: }
232: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.