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