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