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