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