new timeofday and interval timer stuff; itimers need testing
[unix-history] / usr / src / sys / kern / tty_pty.c
... / ...
CommitLineData
1/* tty_pty.c 4.24 82/08/22 */
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#include "../h/param.h"
11#include "../h/systm.h"
12#include "../h/tty.h"
13#include "../h/dir.h"
14#include "../h/user.h"
15#include "../h/conf.h"
16#include "../h/file.h"
17#include "../h/proc.h"
18#include "../h/uio.h"
19
20#if NPTY == 1
21#undef NPTY
22#define NPTY 32 /* crude XXX */
23#endif
24
25#define BUFSIZ 100 /* Chunk size iomoved from user */
26
27/*
28 * pts == /dev/tty[pP]?
29 * ptc == /dev/ptp[pP]?
30 */
31struct tty pt_tty[NPTY];
32struct pt_ioctl {
33 int pt_flags;
34 int pt_gensym;
35 struct proc *pt_selr, *pt_selw;
36 int pt_send;
37} pt_ioctl[NPTY];
38
39#define PF_RCOLL 0x01
40#define PF_WCOLL 0x02
41#define PF_NBIO 0x04
42#define PF_PKT 0x08 /* packet mode */
43#define PF_STOPPED 0x10 /* user told stopped */
44#define PF_REMOTE 0x20 /* remote and flow controlled input */
45#define PF_NOSTOP 0x40
46
47/*ARGSUSED*/
48ptsopen(dev, flag)
49 dev_t dev;
50{
51 register struct tty *tp;
52
53 if (minor(dev) >= NPTY) {
54 u.u_error = ENXIO;
55 return;
56 }
57 tp = &pt_tty[minor(dev)];
58 if ((tp->t_state & TS_ISOPEN) == 0) {
59 ttychars(tp); /* Set up default chars */
60 tp->t_flags = 0; /* No features (nor raw mode) */
61 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
62 u.u_error = EBUSY;
63 return;
64 }
65 if (tp->t_oproc) /* Ctrlr still around. */
66 tp->t_state |= TS_CARR_ON;
67 while ((tp->t_state & TS_CARR_ON) == 0) {
68 tp->t_state |= TS_WOPEN;
69 sleep((caddr_t)&tp->t_rawq, TTIPRI);
70 }
71 (*linesw[tp->t_line].l_open)(dev, tp);
72}
73
74ptsclose(dev)
75 dev_t dev;
76{
77 register struct tty *tp;
78
79 tp = &pt_tty[minor(dev)];
80 (*linesw[tp->t_line].l_close)(tp);
81 ttyclose(tp);
82}
83
84ptsread(dev, uio)
85 dev_t dev;
86 struct uio *uio;
87{
88 register struct tty *tp = &pt_tty[minor(dev)];
89 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
90
91again:
92 if (pti->pt_flags & PF_REMOTE) {
93 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
94 if (u.u_signal[SIGTTIN] == SIG_IGN ||
95 u.u_signal[SIGTTIN] == SIG_HOLD ||
96 /*
97 (u.u_procp->p_flag&SDETACH) ||
98 */
99 u.u_procp->p_flag&SVFORK)
100 return;
101 gsignal(u.u_procp->p_pgrp, SIGTTIN);
102 sleep((caddr_t)&lbolt, TTIPRI);
103 }
104 if (tp->t_rawq.c_cc == 0) {
105 if (tp->t_state & TS_NBIO) {
106 u.u_error = EWOULDBLOCK;
107 return;
108 }
109 sleep((caddr_t)&tp->t_rawq, TTIPRI);
110 goto again;
111 }
112 while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
113 if (ureadc(getc(&tp->t_rawq), uio) < 0) {
114 u.u_error = EFAULT;
115 break;
116 }
117 if (tp->t_rawq.c_cc == 1)
118 (void) getc(&tp->t_rawq);
119 if (tp->t_rawq.c_cc)
120 return;
121 } else
122 if (tp->t_oproc)
123 (*linesw[tp->t_line].l_read)(tp, uio);
124 wakeup((caddr_t)&tp->t_rawq.c_cf);
125 if (pti->pt_selw) {
126 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
127 pti->pt_selw = 0;
128 pti->pt_flags &= ~PF_WCOLL;
129 }
130}
131
132/*
133 * Write to pseudo-tty.
134 * Wakeups of controlling tty will happen
135 * indirectly, when tty driver calls ptsstart.
136 */
137ptswrite(dev, uio)
138 dev_t dev;
139 struct uio *uio;
140{
141 register struct tty *tp;
142
143 tp = &pt_tty[minor(dev)];
144 if (tp->t_oproc)
145 (*linesw[tp->t_line].l_write)(tp, uio);
146}
147
148/*
149 * Start output on pseudo-tty.
150 * Wake up process selecting or sleeping for input from controlling tty.
151 */
152ptsstart(tp)
153 struct tty *tp;
154{
155 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
156
157 if (tp->t_state & TS_TTSTOP)
158 return;
159 if (pti->pt_flags & PF_STOPPED) {
160 pti->pt_flags &= ~PF_STOPPED;
161 pti->pt_send = TIOCPKT_START;
162 }
163 ptcwakeup(tp);
164}
165
166ptcwakeup(tp)
167 struct tty *tp;
168{
169 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
170
171 if (pti->pt_selr) {
172 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
173 pti->pt_selr = 0;
174 pti->pt_flags &= ~PF_RCOLL;
175 }
176 wakeup((caddr_t)&tp->t_outq.c_cf);
177}
178
179/*ARGSUSED*/
180ptcopen(dev, flag)
181 dev_t dev;
182 int flag;
183{
184 register struct tty *tp;
185 struct pt_ioctl *pti;
186
187 if (minor(dev) >= NPTY) {
188 u.u_error = ENXIO;
189 return;
190 }
191 tp = &pt_tty[minor(dev)];
192 if (tp->t_oproc) {
193 u.u_error = EIO;
194 return;
195 }
196 tp->t_oproc = ptsstart;
197 if (tp->t_state & TS_WOPEN)
198 wakeup((caddr_t)&tp->t_rawq);
199 tp->t_state |= TS_CARR_ON;
200 pti = &pt_ioctl[minor(dev)];
201 pti->pt_flags = 0;
202 pti->pt_send = 0;
203}
204
205ptcclose(dev)
206 dev_t dev;
207{
208 register struct tty *tp;
209
210 tp = &pt_tty[minor(dev)];
211 if (tp->t_state & TS_ISOPEN)
212 gsignal(tp->t_pgrp, SIGHUP);
213 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */
214 flushtty(tp, FREAD|FWRITE);
215 tp->t_oproc = 0; /* mark closed */
216}
217
218ptcread(dev, uio)
219 dev_t dev;
220 struct uio *uio;
221{
222 register struct tty *tp;
223 struct pt_ioctl *pti;
224
225 tp = &pt_tty[minor(dev)];
226 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
227 return;
228 pti = &pt_ioctl[minor(dev)];
229 if (pti->pt_flags & PF_PKT) {
230 if (pti->pt_send) {
231 (void) ureadc(pti->pt_send, uio);
232 pti->pt_send = 0;
233 return;
234 }
235 (void) ureadc(0, uio);
236 }
237 while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
238 if (pti->pt_flags&PF_NBIO) {
239 u.u_error = EWOULDBLOCK;
240 return;
241 }
242 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
243 }
244 while (tp->t_outq.c_cc && uio->uio_resid > 0)
245 if (ureadc(getc(&tp->t_outq), uio) < 0) {
246 u.u_error = EFAULT;
247 break;
248 }
249 if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
250 if (tp->t_state&TS_ASLEEP) {
251 tp->t_state &= ~TS_ASLEEP;
252 wakeup((caddr_t)&tp->t_outq);
253 }
254 if (tp->t_wsel) {
255 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
256 tp->t_wsel = 0;
257 tp->t_state &= ~TS_WCOLL;
258 }
259 }
260}
261
262ptsstop(tp, flush)
263 register struct tty *tp;
264 int flush;
265{
266 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
267
268 /* note: FLUSHREAD and FLUSHWRITE already ok */
269 if (flush == 0) {
270 flush = TIOCPKT_STOP;
271 pti->pt_flags |= PF_STOPPED;
272 } else {
273 pti->pt_flags &= ~PF_STOPPED;
274 }
275 pti->pt_send |= flush;
276 ptcwakeup(tp);
277}
278
279ptcselect(dev, rw)
280 dev_t dev;
281 int rw;
282{
283 register struct tty *tp = &pt_tty[minor(dev)];
284 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
285 struct proc *p;
286 int s;
287
288 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
289 return (1);
290 s = spl5();
291 switch (rw) {
292
293 case FREAD:
294 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
295 splx(s);
296 return (1);
297 }
298 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
299 pti->pt_flags |= PF_RCOLL;
300 else
301 pti->pt_selr = u.u_procp;
302 break;
303
304 case FWRITE:
305 if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
306 splx(s);
307 return (1);
308 }
309 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
310 pti->pt_flags |= PF_WCOLL;
311 else
312 pti->pt_selw = u.u_procp;
313 break;
314 }
315 splx(s);
316 return (0);
317}
318
319ptcwrite(dev, uio)
320 dev_t dev;
321 struct uio *uio;
322{
323 register struct tty *tp;
324 register char *cp, *ce;
325 register int cc;
326 char locbuf[BUFSIZ];
327 int cnt = 0;
328 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
329
330 tp = &pt_tty[minor(dev)];
331 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
332 return;
333 do {
334 register struct iovec *iov;
335
336 if (uio->uio_iovcnt == 0)
337 break;
338 iov = uio->uio_iov;
339 if (iov->iov_len == 0) {
340 uio->uio_iovcnt--;
341 uio->uio_iov++;
342 if (uio->uio_iovcnt < 0)
343 panic("ptcwrite");
344 continue;
345 }
346 cc = MIN(iov->iov_len, BUFSIZ);
347 cp = locbuf;
348 u.u_error = uiomove(cp, cc, UIO_WRITE, uio);
349 if (u.u_error)
350 break;
351 ce = cp + cc;
352again:
353 if (pti->pt_flags & PF_REMOTE) {
354 if (tp->t_rawq.c_cc) {
355 if (pti->pt_flags & PF_NBIO) {
356 iov->iov_base -= ce - cp;
357 iov->iov_len += ce - cp;
358 uio->uio_resid += ce - cp;
359 uio->uio_offset -= ce - cp;
360 u.u_error = EWOULDBLOCK;
361 return;
362 }
363 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
364 goto again;
365 }
366 (void) b_to_q(cp, cc, &tp->t_rawq);
367 (void) putc(0, &tp->t_rawq);
368 wakeup((caddr_t)&tp->t_rawq);
369 return;
370 }
371 while (cp < ce) {
372 while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
373 wakeup((caddr_t)&tp->t_rawq);
374 if (tp->t_state & TS_NBIO) {
375 iov->iov_base -= ce - cp;
376 iov->iov_len += ce - cp;
377 uio->uio_resid += ce - cp;
378 uio->uio_offset -= ce - cp;
379 if (cnt == 0)
380 u.u_error = EWOULDBLOCK;
381 return;
382 }
383 /* Better than just flushing it! */
384 /* Wait for something to be read */
385 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
386 goto again;
387 }
388 (*linesw[tp->t_line].l_rint)(*cp++, tp);
389 cnt++;
390 }
391 } while (uio->uio_resid);
392}
393
394/*ARGSUSED*/
395ptyioctl(dev, cmd, data, flag)
396 caddr_t data;
397 dev_t dev;
398{
399 register struct tty *tp = &pt_tty[minor(dev)];
400 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
401
402 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
403 if (cdevsw[major(dev)].d_open == ptcopen)
404 switch (cmd) {
405
406 case TIOCPKT:
407 if (*(int *)data)
408 pti->pt_flags |= PF_PKT;
409 else
410 pti->pt_flags &= ~PF_PKT;
411 return;
412
413 case TIOCREMOTE:
414 if (*(int *)data)
415 pti->pt_flags |= PF_REMOTE;
416 else
417 pti->pt_flags &= ~PF_REMOTE;
418 flushtty(tp, FREAD|FWRITE);
419 return;
420
421 case FIONBIO:
422 if (*(int *)data)
423 pti->pt_flags |= PF_NBIO;
424 else
425 pti->pt_flags &= ~PF_NBIO;
426 return;
427
428 case TIOCSETP:
429 while (getc(&tp->t_outq) >= 0)
430 ;
431 break;
432 }
433 if (ttioctl(tp, cmd, data, dev) == 0)
434 u.u_error = ENOTTY;
435 { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
436 tp->t_un.t_chr.t_startc == ('q'&037));
437 if (pti->pt_flags & PF_NOSTOP) {
438 if (stop) {
439 pti->pt_send &= TIOCPKT_NOSTOP;
440 pti->pt_send |= TIOCPKT_DOSTOP;
441 pti->pt_flags &= ~PF_NOSTOP;
442 ptcwakeup(tp);
443 }
444 } else {
445 if (stop == 0) {
446 pti->pt_send &= ~TIOCPKT_DOSTOP;
447 pti->pt_send |= TIOCPKT_NOSTOP;
448 pti->pt_flags |= PF_NOSTOP;
449 ptcwakeup(tp);
450 }
451 }
452 }
453}
454#endif