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