|
|
1.1 root 1: #include "../chunix/chsys.h"
2: #include "../chunix/chconf.h"
3: #include "../chaos/chaos.h"
4: #include "../chaos/dev.h"
5: #include "../h/inode.h"
6: #include "../h/file.h"
7: #include "../h/tty.h"
8: #include "../h/dir.h"
9: #include "../h/user.h"
10: #include "../h/conf.h"
11: /*
12: * This file contains functions for treating a chaos channel as a UNIX tty
13: */
14: #include "cht.h"
15: struct tty cht_tty[NCHT * 16];
16: int cht_cnt = NCHT * 16;
17:
18: /*
19: * Do the additional work necessary to open a channel as a UNIX tty.
20: * Basically the existence of an associated connection is much like
21: * the existence of a carrier.
22: */
23: /* ARGSUSED */
24: chtopen(dev, flag)
25: dev_t dev;
26: {
27: register struct tty *tp;
28: register int unit;
29: int chtstart(), chtinput();
30:
31: unit = minor(dev);
32: if (unit >= cht_cnt) {
33: u.u_error = ENXIO;
34: return;
35: }
36: tp = &cht_tty[unit];
37: if (tp->t_state & XCLUDE && u.u_uid != 0) {
38: u.u_error = EBUSY;
39: return;
40: }
41: tp->t_state |= WOPEN;
42: tp->t_oproc = chtstart;
43: tp->t_iproc = chtinput;
44: if ((tp->t_state&ISOPEN) == 0) {
45: ttychars(tp);
46: tp->t_ispeed = B9600;
47: tp->t_ospeed = B9600;
48: tp->t_flags = ODDP|EVENP|ECHO;
49: tp->t_state |= HUPCLS;
50: }
51: tp->t_lstate |= LSCHAOS;
52: LOCK;
53: /*
54: * Since ttyclose forces CARR_ON off, we turn it on again if
55: * the connection is still around.
56: */
57: if (tp->t_addr)
58: tp->t_state |= CARR_ON;
59: else while ((tp->t_state & CARR_ON) == 0)
60: sleep((caddr_t)&tp->t_rawq, TTIPRI);
61: UNLOCK;
62: tp->t_line = NTTYDISC;
63: (*linesw[tp->t_line].l_open)(dev, tp);
64: }
65: /*
66: * Close the tty associated with the given connection.
67: */
68: chtclose(dev, flag)
69: dev_t dev;
70: int flag;
71: {
72: register struct connection *conn;
73: register struct tty *tp;
74:
75: tp = &cht_tty[minor(dev)];
76: (*linesw[tp->t_line].l_close)(tp);
77: conn = (struct connection *)tp->t_addr;
78: if (tp->t_state & HUPCLS || conn->cn_state != CSOPEN) {
79: /*
80: * We call the main close routine in RECORD mode, which
81: * closes the connection directly.
82: */
83: conn->cn_mode = CHRECORD;
84: chclose(conn, flag);
85: tp->t_addr = 0;
86: tp->t_state &= ~CARR_ON;
87: tp->t_lstate &= ~LSCHAOS;
88: }
89: ttyclose(tp);
90: }
91:
92: /*
93: * Read from a chaos channel that is a tty.
94: */
95: chtread(dev)
96: dev_t dev;
97: {
98: register struct tty *tp = &cht_tty[minor(dev)];
99: register struct connection *conn = (struct connection *)tp->t_addr;
100: /*
101: * Since ttys are quite possibly interactive, be sure
102: * to flush any output when input is desired. It would
103: * be soon anyway due to timeouts.
104: */
105: spl6();
106: if (conn->cn_toutput != NOPKT && !chtfull(conn))
107: ch_sflush(conn);
108: spl0();
109: (*linesw[tp->t_line].l_read)(tp);
110: }
111: int chttyraw;
112: /*
113: * Write to a chaos channel that is a tty.
114: */
115: chtwrite(dev)
116: dev_t dev;
117: {
118: register struct tty *tp = &cht_tty[minor(dev)];
119:
120: if (tp->t_flags & RAW) {
121: chttyraw++;
122: chwrite((struct connection *)tp->t_addr);
123: } else
124: (*linesw[tp->t_line].l_write)(tp);
125: }
126: /*
127: * We only allow tty ioctl's for a chaos tty.
128: * We could also allow chaos ioctl's if needed.
129: */
130: chtioctl(dev, cmd, addr, flag)
131: dev_t dev;
132: caddr_t addr;
133: {
134: register struct tty *tp = &cht_tty[minor(dev)];
135:
136: cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
137: if (cmd == 0)
138: return;
139: if (ttioctl(tp, cmd, addr, flag)) {
140: if (cmd==TIOCSETP || cmd==TIOCSETN) {
141: /*
142: * Send virtual terminal codes here?
143: */
144: /* chparam(conn); */
145: }
146: } else switch(cmd) {
147: /*
148: * We need a remote terminal protocol here. - Yick.
149: */
150: case TIOCSBRK:
151: /* maybe someday a code for break on output ? */
152: break;
153: case TIOCCBRK:
154: break;
155: case TIOCSDTR:
156: break;
157: case TIOCCDTR:
158: break;
159: default:
160: u.u_error = ENOTTY;
161: }
162: }
163: /*
164: * Interrupt routine called when a new packet is available for a tty channel
165: * Basically empty the packet into the tty system.
166: * Called both from interrupt level when the read packet queue becomes
167: * non-empty and also (at high priority) from top level. THe top level
168: * call is needed to retrieve data not queued at interrupt time due to
169: * input queue high water mark reached.
170: */
171: chtrint(conn)
172: struct connection *conn;
173: {
174: register struct packet *pkt;
175: register struct tty *tp = conn->cn_ttyp;
176: register char *cp;
177:
178: while ((pkt = conn->cn_rhead) != NOPKT) {
179: if (ISDATOP(pkt) && conn->cn_state == CSOPEN)
180: for (cp = &pkt->pk_cdata[conn->cn_roffset];
181: pkt->pk_len != 0; pkt->pk_len--)
182: if (tp->t_rawq.c_cc + tp->t_canq.c_cc >=
183: TTYHOG) {
184: conn->cn_roffset = cp - pkt->pk_cdata;
185: return;
186: } else
187: (*linesw[tp->t_line].l_rint)
188: (*cp++ & 0377, tp);
189: ch_read(conn);
190: }
191: /*
192: * Flush any output since we might have echoed something at
193: * interrupt level.
194: */
195: if (conn->cn_toutput != NOPKT)
196: ch_sflush(conn);
197: }
198: /*
199: * Get more data if possible. This is called from ttread (ntread) to
200: * see if more data can be read from the connection.
201: * It is only needed to account for the case where packets are not
202: * completely emptied at interrupt level due to input clist buffer
203: * overflow (>TTYHOG). In this respect, chaos connections win better
204: * than ttys, which just throw the data away.
205: */
206: chtinput(tp)
207: register struct tty *tp;
208: {
209: register int opl = spl6();
210:
211: chtrint((struct connection *)tp->t_addr);
212: splx(opl);
213: }
214: /*
215: * Interrupt routine called when more packets can again be sent after things
216: * block due to window full.
217: */
218: chtxint(conn)
219: register struct connection *conn;
220: {
221: register struct tty *tp = conn->cn_ttyp;
222: register int s = spl6();
223:
224: if (tp->t_state & ASLEEP) {
225: tp->t_state &= ~ASLEEP;
226: wakeup((caddr_t)&tp->t_outq);
227: }
228: if (tp->t_line)
229: (*linesw[tp->t_line].l_start)(tp);
230: else
231: chtstart(tp);
232: splx(s);
233: }
234: /*
235: * Are we output flow controlled?
236: */
237: chtblocked(tp)
238: struct tty *tp;
239: {
240: register struct connection *conn = (struct connection *)tp->t_addr;
241:
242: return chtfull(conn);
243: }
244: /*
245: * Are we empty on output?
246: */
247: chtnobuf(tp)
248: struct tty *tp;
249: {
250: register struct connection *conn = (struct connection *)tp->t_addr;
251:
252: return !conn->cn_toutput;
253: }
254: /*
255: * Flush any buffered output that we can.
256: * Called from high priority.
257: */
258: chtflush(tp)
259: struct tty *tp;
260: {
261: register struct connection *conn = (struct connection *)tp->t_addr;
262:
263:
264: if (conn->cn_toutput) {
265: ch_free((caddr_t)conn->cn_toutput);
266: conn->cn_toutput = NOPKT;
267: }
268: }
269:
270: /*
271: * Start sending any buffered output.
272: * We just start sending any packet that is partially full.
273: */
274: chtstart(tp)
275: struct tty *tp;
276: {
277: ch_sflush((struct connection *)tp->t_addr);
278: }
279: /*
280: * Put out one character and return non-zero if we couldn't
281: */
282: chtputc(c, tp)
283: char c;
284: struct tty *tp;
285: {
286: return chtout(&c, 1, tp);
287: }
288: /*
289: * Send a contiguous array of bytes.
290: * Return the number we can't accept now.
291: * Packet allocation strategy:
292: * We allocate a packet that is at least large enough to hold all bytes
293: * remaining to be sent in this system call. We rely on the fact that
294: * packets are really powers of two in size and at least 16 bytes of data,
295: * since we don't round up our request at all.
296: * If our "clever" request fails, we try for a small packet.
297: */
298: chtout(cp, cc, tp)
299: register char *cp;
300: struct tty *tp;
301: {
302: register struct connection *conn = (struct connection *)tp->t_addr;
303: register struct packet *pkt;
304: register int n;
305: int sps = spl6();
306: extern int ttrstrt();
307:
308: if (conn->cn_state == CSOPEN &&
309: (tp->t_state & (TIMEOUT|BUSY|TTSTOP)) == 0) {
310: while (cc != 0) {
311: if ((pkt = conn->cn_toutput) == NOPKT) {
312: n = chtfull(conn) ? CHMAXDATA :
313: chroundup(u.u_count + cc);
314: if ((pkt = pkalloc(n, 1)) == NOPKT) {
315: n = CHMINDATA;
316: if ((pkt = pkalloc(n, 1)) == NOPKT)
317: break;
318: }
319: pkt->pk_op = DATOP;
320: pkt->pk_type = 0;
321: pkt->pk_lenword = 0;
322: conn->cn_troom = n;
323: conn->cn_toutput = pkt;
324: }
325: if ((n = cc) > conn->cn_troom)
326: n = conn->cn_troom;
327: if (n != 0) {
328: chmove(cp, &pkt->pk_cdata[pkt->pk_lenword], n);
329: pkt->pk_time = Chclock;
330: pkt->pk_lenword += n;
331: cp += n;
332: }
333: cc -= n;
334: if ((conn->cn_troom -= n) == 0)
335: if (chtfull(conn))
336: break;
337: else
338: ch_sflush(conn);
339: }
340: }
341: splx(sps);
342: return (cc);
343: }
344: /*
345: * Process a connection state change for a tty.
346: */
347: chtnstate(conn)
348: register struct connection *conn;
349: {
350: register struct tty *tp;
351:
352: tp = conn->cn_ttyp;
353: switch (conn->cn_state) {
354: /*
355: * This shouldn't really happen since the connection shouldn't
356: * become a tty until it is open.
357: */
358: case CSOPEN:
359: if ((tp->t_state & CARR_ON) == 0) {
360: wakeup((caddr_t)&tp->t_rawq);
361: tp->t_state |= CARR_ON;
362: }
363: break;
364: case CSCLOSED:
365: case CSINCT:
366: case CSLOST:
367: if (tp->t_state & CARR_ON) {
368: if ((tp->t_local & LNOHANG) == 0 &&
369: tp->t_state & ISOPEN) {
370: gsignal(tp->t_pgrp, SIGHUP);
371: #ifdef SIGCONT
372: gsignal(tp->t_pgrp, SIGCONT);
373: #endif
374: flushtty(tp, FREAD|FWRITE);
375: }
376: tp->t_state &= ~CARR_ON;
377: } else if (!(tp->t_state & ISOPEN)) {
378: tp->t_addr = 0;
379: ch_close(conn, NOPKT, 1);
380: ch_buffree();
381: }
382: break;
383: default:
384: panic("chtnstate");
385: }
386: }
387:
388:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.