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