|
|
1.1 root 1: /*
2: * File: pty.c
3: *
4: * Purpose: pseudoterminal device driver
5: *
6: * Master devices are named /dev/pty[pqrs][0-f].
7: * Corresponding slaves are /dev/tty[pqrs][0-f].
8: *
9: * Minor numbers are 0..127 assigned in increasing order,
10: * plus 128 for master device.
11: *
12: * Output written to master appears as input to slave and
13: * vice versa. Data path is:
14: *
15: * app master slave line app
16: * using device shunt device disc. using
17: * master driver driver module slave
18: *
19: * slave read does ttread() which is fed by ttin()
20: * master write does ttin()
21: *
22: * slave write does ttwrite() which is fed by ttout()
23: * master read does ttout()
24: *
25: * $Log: pty.c,v $
26: * Revision 1.4 93/04/14 10:12:10 root
27: * r75
28: *
29: * Revision 1.3 92/07/16 16:35:29 hal
30: * Kernel #58
31: *
32: * Revision 1.2 92/03/18 07:45:33 hal
33: * master device polling added
34: *
35: * Revision 1.1 92/03/16 12:57:31 hal
36: * Initial revision
37: *
38: */
39:
40: /*
41: * -----------------------------------------------------------------
42: * Includes.
43: */
44: #include <sys/coherent.h>
45: #include <sys/stat.h>
46: #include <sys/proc.h>
47: #include <sys/tty.h> /* indirectly includes sgtty.h */
48: #include <sys/con.h>
49: #include <sys/devices.h>
50: #include <errno.h>
51: #include <poll.h>
52: #include <sys/sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */
53:
54: /*
55: * -----------------------------------------------------------------
56: * Definitions.
57: * Constants.
58: * Macros with argument lists.
59: * Typedefs.
60: * Enums.
61: */
62:
63: #define channel(dev) (dev & 0x7F)
64: #define master(dev) (dev & 0x80)
65: #ifdef _I386
66: #define EEBUSY EBUSY
67: #else
68: #define EEBUSY EDBUSY
69: #endif
70:
71: /*
72: * Explanation of p_mopen values:
73: * 0 - master is closed
74: * 1 - master open, waiting for slave to open
75: * 2 - master and slave both open
76: * 3 - master open, slave has closed
77: */
78:
79: typedef struct pty {
80: TTY p_tp;
81: event_t p_iev;
82: event_t p_oev;
83: char p_mopen;
84: char p_asleep; /* master is asleep in read or write awaiting slave */
85: char p_ttwr; /* slave is suspended in mid ttwrite() */
86: } PTY;
87:
88: /*
89: * -----------------------------------------------------------------
90: * Functions.
91: * Import Functions.
92: * Export Functions.
93: * Local Functions.
94: */
95: int nulldev();
96: void pollwake();
97:
98: /*
99: * Configuration functions (local functions).
100: */
101: static void ptyclose();
102: static void ptyioctl();
103: static void ptyload();
104: static void ptyopen();
105: static void ptyread();
106: static void ptyunload();
107: static void ptywrite();
108: static void ptystart();
109: static int ptypoll();
110:
111: /*
112: * Support functions (local functions).
113: */
114: static void ptycycle();
115:
116: /*
117: * -----------------------------------------------------------------
118: * Global Data.
119: * Import Variables.
120: * Export Variables.
121: * Local Variables.
122: */
123: int NUPTY = 8;
124:
125: /*
126: * Configuration table (export data).
127: */
128: CON ptycon ={
129: DFCHR|DFPOL, /* Flags */
130: PTY_MAJOR, /* Major index */
131: ptyopen, /* Open */
132: ptyclose, /* Close */
133: nulldev, /* Block */
134: ptyread, /* Read */
135: ptywrite, /* Write */
136: ptyioctl, /* Ioctl */
137: nulldev, /* Powerfail */
138: nulldev, /* Timeout */
139: ptyload, /* Load */
140: ptyunload, /* Unload */
141: ptypoll /* Poll */
142: };
143:
144: static PTY * p;
145:
146: /*
147: * -----------------------------------------------------------------
148: * Code.
149: */
150:
151: /*
152: * ptyload()
153: */
154: static void
155: ptyload()
156: {
157: int i;
158: TTY * tp;
159:
160: if ((p = (PTY *)kalloc(NUPTY*sizeof(PTY))) == 0) {
161: printf("ptyload: can't allocate %s pty's\n", NUPTY);
162: return;
163: }
164: kclear(p, NUPTY*sizeof(PTY));
165: for (i = 0; i < NUPTY; i++) {
166: tp = &p[i].p_tp;
167: tp->t_cs_sel = cs_sel();
168: tp->t_start = ptystart;
169: tp->t_param = nulldev;
170: tp->t_ddp = (char *)i;
171: }
172: }
173:
174: /*
175: * ptyunload()
176: */
177: static void
178: ptyunload()
179: {
180: if (p)
181: kfree(p);
182: printf("pty driver unloaded\n");
183: }
184:
185: /*
186: * ptyopen()
187: */
188: static void
189: ptyopen(dev, mode)
190: dev_t dev;
191: int mode;
192: {
193: int chan = channel(dev);
194: PTY * pp = p + chan;
195: TTY * tp = &pp->p_tp;
196:
197: if (chan >= NUPTY) {
198: u.u_error = ENXIO;
199: goto open_done;
200: }
201:
202: if (master(dev)){
203: if (pp->p_mopen) {
204: u.u_error = EEBUSY;
205: goto open_done;
206: }
207: if (tp->t_open)
208: pp->p_mopen = 2;
209: else
210: pp->p_mopen = 1;
211: wakeup((char *)(&tp->t_open));
212: ptycycle(chan);
213: } else {
214: tp->t_flags |= T_HOPEN | T_STOP;
215: for (;;) { /* wait for carrier */
216: if (pp->p_mopen)
217: break;
218: #ifdef _I386
219: x_sleep((char *)(&tp->t_open), pritty, slpriSigCatch,
220: "ptycd");
221: #else
222: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT,
223: SVTTOUT, "ptycd");
224: #endif
225: /* PTY driver is waiting for carrier. */
226: if (SELF->p_ssig && nondsig()) { /* signal? */
227: u.u_error = EINTR;
228: tp->t_flags &= ~(T_HOPEN | T_STOP);
229: goto open_done;
230: }
231: }
232: tp->t_flags |= T_CARR;
233: tp->t_flags &= ~(T_HOPEN | T_STOP);
234: ttopen(tp);
235: tp->t_open++;
236: ttsetgrp(tp, dev, mode);
237: if (pp->p_mopen == 1 || pp->p_mopen == 3)
238: pp->p_mopen = 2;
239: }
240: open_done:;
241: }
242:
243: /*
244: * ptyclose()
245: */
246: static void
247: ptyclose(dev, mode)
248: dev_t dev;
249: int mode;
250: {
251: int chan = channel(dev);
252: PTY * pp = p + chan;
253: TTY * tp = &pp->p_tp;
254:
255: if (chan >= NUPTY) {
256: u.u_error = ENXIO;
257: return;
258: }
259:
260: if (master(dev)){
261: if (pp->p_mopen) {
262: tp->t_flags &= ~T_CARR;
263: tthup(tp);
264: pp->p_mopen = 0;
265: }
266: } else {
267: if (--tp->t_open == 0) {
268: ttclose(tp);
269: if (pp->p_mopen == 2)
270: pp->p_mopen = 3;
271: wakeup(&pp->p_mopen);
272: }
273: }
274: }
275:
276: /*
277: * ptyread()
278: */
279: static void
280: ptyread(dev, iop)
281: dev_t dev;
282: register IO * iop;
283: {
284: int chan = channel(dev);
285: PTY * pp = p + chan;
286: TTY * tp = &pp->p_tp;
287: int c;
288:
289: if (master(dev)){
290: int char_read = 0;
291:
292: while (iop->io_ioc) {
293: c = ttout(tp);
294: if (c == -1) { /* nothing to fetch */
295: if (char_read) {
296: ttstart(tp);
297: goto read_done;
298: }
299: if (iop->io_flag & IONDLY) {
300: u.u_error = EAGAIN;
301: goto read_done;
302: }
303: if (pp->p_mopen == 3) {
304: u.u_error = EIO;
305: goto read_done;
306: }
307: ttstart(tp);
308: pp->p_asleep = 1;
309: #ifdef _I386
310: x_sleep(&pp->p_mopen, pritty, slpriSigCatch,
311: "ptyread");
312: #else
313: v_sleep(&pp->p_mopen, CVTTOUT, IVTTOUT,
314: SVTTOUT, "ptyread");
315: #endif
316: /* The PTY driver is waiting for a read. */
317: if (SELF->p_ssig && nondsig()) {
318: u.u_error = EINTR;
319: goto read_done;
320: }
321: } else {
322: ioputc(c, iop);
323: char_read = 1;
324: }
325: }
326: read_done:;
327: } else {
328: #if 0
329: if (pp->p_asleep) {
330: pp->p_asleep = 0;
331: wakeup(&pp->p_mopen);
332: }
333: pollwake(&pp->p_oev);
334: ttread(tp, iop);
335: #else
336: pp->p_asleep = 0; /* ttread0 will awaken the sleeper */
337: ttread0(tp,iop,wakeup,&pp->p_mopen,pollwake,&pp->p_oev);
338: #endif
339: }
340: }
341:
342: /*
343: * ptywrite()
344: */
345: static void
346: ptywrite(dev, iop)
347: dev_t dev;
348: register IO * iop;
349: {
350: int chan = channel(dev);
351: PTY * pp = p + chan;
352: TTY * tp = &pp->p_tp;
353: int c;
354:
355: if (master(dev)){
356: while (iop->io_ioc) {
357: if (!ttinp(tp)) {
358: if (iop->io_flag & IONDLY) {
359: u.u_error = EAGAIN;
360: goto write_done;
361: }
362: if (pp->p_mopen == 3) {
363: u.u_error = EIO;
364: goto write_done;
365: }
366: pp->p_asleep = 1;
367: #ifdef _I386
368: x_sleep(&pp->p_mopen, pritty, slpriSigCatch,
369: "ptywrite");
370: #else
371: v_sleep(&pp->p_mopen, CVTTOUT, IVTTOUT,
372: SVTTOUT, "ptywrite");
373: #endif
374: /* The PTY driver is waiting for a write. */
375: if (SELF->p_ssig && nondsig()) { /* signal? */
376: u.u_error = EINTR;
377: goto write_done;
378: }
379: }
380: c = iogetc(iop);
381: ttin(tp, c);
382: }
383: wakeup(&pp->p_mopen);
384: } else {
385: pp->p_ttwr = 1;
386: ttwrite0(tp,iop,wakeup,&pp->p_mopen,pollwake,&pp->p_iev);
387: pp->p_ttwr = 0;
388: }
389: write_done:;
390: }
391:
392: /*
393: * ptyioctl()
394: */
395: static void
396: ptyioctl(dev, com, vec)
397: dev_t dev;
398: int com;
399: struct sgttyb *vec;
400: {
401: int chan = channel(dev);
402: PTY * pp = p + chan;
403: TTY * tp = &pp->p_tp;
404:
405: if (master(dev)){
406: u.u_error = EINVAL;
407: } else {
408: ttioctl(tp, com, vec);
409: }
410: }
411:
412: /*
413: * ptystart()
414: */
415: static void
416: ptystart(tp)
417: TTY * tp;
418: {
419: int chan = (int)tp->t_ddp;
420: PTY * pp = p + chan;
421:
422: if (chan >= 0 && chan < NUPTY) {
423: if (pp->p_ttwr)
424: wakeup(&pp->p_mopen);
425: }
426: }
427:
428: /*
429: * ptypoll()
430: */
431: static int
432: ptypoll(dev, ev, msec)
433: dev_t dev;
434: int ev;
435: int msec;
436: {
437: int chan = channel(dev);
438: PTY * pp = p + chan;
439: TTY * tp = &pp->p_tp;
440: int ret;
441:
442: if (master(dev)) {
443: /*
444: * Priority polls not supported.
445: */
446: ev &= (POLLIN | POLLOUT);
447:
448: /*
449: * Input poll with no data present.
450: */
451: if ((ev & POLLIN) && (ttoutp(tp) == 0)) {
452:
453: /*
454: * Blocking input poll.
455: */
456: if (msec != 0) {
457: pollopen(&pp->p_iev);
458: }
459:
460: /*
461: * Second look to avoid interrupt race.
462: */
463: if (ttoutp(tp) == 0)
464: ev &= ~POLLIN;
465: }
466:
467: /*
468: * Output poll with no space.
469: */
470: if ((ev & POLLOUT) && (ttinp(tp) == 0)) {
471:
472: /*
473: * Blocking output poll.
474: */
475: if (msec != 0) {
476: pollopen(&pp->p_oev);
477: }
478:
479: /*
480: * Second look to avoid interrupt race.
481: */
482: if (ttinp(tp) == 0)
483: ev &= ~POLLOUT;
484: }
485:
486: ret = ev;
487: } else
488: ret = ttpoll(tp, ev, msec);
489: return ret;
490: }
491:
492: /*
493: * ptycycle()
494: *
495: * Do a wakeup of any sleeping pty's at regular intervals.
496: */
497: static void
498: ptycycle(chan)
499: int chan;
500: {
501: PTY * pp = p + chan;
502: TTY * tp = &pp->p_tp;
503:
504: /*
505: * Do wakeups.
506: */
507: if (pp->p_asleep || pp->p_ttwr) {
508: wakeup(&pp->p_mopen);
509: pollwake(&pp->p_oev);
510: }
511:
512: /*
513: * Schedule next cycle.
514: */
515: if (pp->p_mopen)
516: timeout(&tp->t_rawtim, HZ/10, ptycycle, chan);
517: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.