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