FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_pty.c
1 /*
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
34 * $FreeBSD: src/sys/kern/tty_pty.c,v 1.39.2.2 1999/09/05 08:15:27 peter Exp $
35 */
36
37 /*
38 * Pseudo-teletype Driver
39 * (Actually two drivers, requiring two entries in 'cdevsw')
40 */
41 #include "pty.h" /* XXX */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/ioctl.h>
46 #include <sys/proc.h>
47 #include <sys/tty.h>
48 #include <sys/conf.h>
49 #include <sys/file.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52 #include <sys/vnode.h>
53 #include <sys/signalvar.h>
54
55 #ifdef DEVFS
56 #include <sys/devfsext.h>
57 #endif /*DEVFS*/
58
59 #ifdef notyet
60 static void ptyattach __P((int n));
61 #endif
62 static void ptsstart __P((struct tty *tp));
63 static void ptcwakeup __P((struct tty *tp, int flag));
64
65 static d_open_t ptsopen;
66 static d_close_t ptsclose;
67 static d_read_t ptsread;
68 static d_write_t ptswrite;
69 static d_ioctl_t ptyioctl;
70 static d_stop_t ptsstop;
71 static d_devtotty_t ptydevtotty;
72 static d_open_t ptcopen;
73 static d_close_t ptcclose;
74 static d_read_t ptcread;
75 static d_write_t ptcwrite;
76 static d_select_t ptcselect;
77
78 #define CDEV_MAJOR_S 5
79 #define CDEV_MAJOR_C 6
80 static struct cdevsw pts_cdevsw =
81 { ptsopen, ptsclose, ptsread, ptswrite, /*5*/
82 ptyioctl, ptsstop, nullreset, ptydevtotty,/* ttyp */
83 ttselect, nommap, NULL, "pts", NULL, -1 };
84
85 static struct cdevsw ptc_cdevsw =
86 { ptcopen, ptcclose, ptcread, ptcwrite, /*6*/
87 ptyioctl, nullstop, nullreset, ptydevtotty,/* ptyp */
88 ptcselect, nommap, NULL, "ptc", NULL, -1 };
89
90
91 #if NPTY == 1
92 #undef NPTY
93 #define NPTY 32 /* crude XXX */
94 #warning You have only one pty defined, redefining to 32.
95 #endif
96
97 #ifdef DEVFS
98 #define MAXUNITS (8 * 32)
99 static void *devfs_token_pts[MAXUNITS];
100 static void *devfs_token_ptc[MAXUNITS];
101 static const char jnames[] = "pqrsPQRS";
102 #if NPTY > MAXUNITS
103 #undef NPTY
104 #define NPTY MAXUNITS
105 #warning Can't have more than 256 pty's with DEVFS defined.
106 #endif
107 #endif
108
109 #define BUFSIZ 100 /* Chunk size iomoved to/from user */
110
111 /*
112 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
113 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
114 */
115 static struct tty pt_tty[NPTY]; /* XXX */
116 static struct pt_ioctl {
117 int pt_flags;
118 struct selinfo pt_selr, pt_selw;
119 u_char pt_send;
120 u_char pt_ucntl;
121 } pt_ioctl[NPTY]; /* XXX */
122 static int npty = NPTY; /* for pstat -t */
123
124 #define PF_PKT 0x08 /* packet mode */
125 #define PF_STOPPED 0x10 /* user told stopped */
126 #define PF_REMOTE 0x20 /* remote and flow controlled input */
127 #define PF_NOSTOP 0x40
128 #define PF_UCNTL 0x80 /* user control mode */
129
130 #ifdef notyet
131 /*
132 * Establish n (or default if n is 1) ptys in the system.
133 *
134 * XXX cdevsw & pstat require the array `pty[]' to be an array
135 */
136 static void
137 ptyattach(n)
138 int n;
139 {
140 char *mem;
141 register u_long ntb;
142 #define DEFAULT_NPTY 32
143
144 /* maybe should allow 0 => none? */
145 if (n <= 1)
146 n = DEFAULT_NPTY;
147 ntb = n * sizeof(struct tty);
148 mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
149 M_DEVBUF, M_WAITOK);
150 pt_tty = (struct tty *)mem;
151 mem = (char *)ALIGN(mem + ntb);
152 pt_ioctl = (struct pt_ioctl *)mem;
153 npty = n;
154 }
155 #endif
156
157 /*ARGSUSED*/
158 static int
159 ptsopen(dev, flag, devtype, p)
160 dev_t dev;
161 int flag, devtype;
162 struct proc *p;
163 {
164 register struct tty *tp;
165 int error;
166
167 if (minor(dev) >= npty)
168 return (ENXIO);
169 tp = &pt_tty[minor(dev)];
170 if ((tp->t_state & TS_ISOPEN) == 0) {
171 ttychars(tp); /* Set up default chars */
172 tp->t_iflag = TTYDEF_IFLAG;
173 tp->t_oflag = TTYDEF_OFLAG;
174 tp->t_lflag = TTYDEF_LFLAG;
175 tp->t_cflag = TTYDEF_CFLAG;
176 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
177 ttsetwater(tp); /* would be done in xxparam() */
178 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
179 return (EBUSY);
180 if (tp->t_oproc) /* Ctrlr still around. */
181 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
182 while ((tp->t_state & TS_CARR_ON) == 0) {
183 if (flag&FNONBLOCK)
184 break;
185 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
186 "ptsopn", 0);
187 if (error)
188 return (error);
189 }
190 error = (*linesw[tp->t_line].l_open)(dev, tp);
191 if (error == 0)
192 ptcwakeup(tp, FREAD|FWRITE);
193 return (error);
194 }
195
196 static int
197 ptsclose(dev, flag, mode, p)
198 dev_t dev;
199 int flag, mode;
200 struct proc *p;
201 {
202 register struct tty *tp;
203 int err;
204
205 tp = &pt_tty[minor(dev)];
206 err = (*linesw[tp->t_line].l_close)(tp, flag);
207 ptsstop(tp, FREAD|FWRITE);
208 (void) ttyclose(tp);
209 return (err);
210 }
211
212 static int
213 ptsread(dev, uio, flag)
214 dev_t dev;
215 struct uio *uio;
216 int flag;
217 {
218 struct proc *p = curproc;
219 register struct tty *tp = &pt_tty[minor(dev)];
220 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
221 int error = 0;
222
223 again:
224 if (pti->pt_flags & PF_REMOTE) {
225 while (isbackground(p, tp)) {
226 if ((p->p_sigignore & sigmask(SIGTTIN)) ||
227 (p->p_sigmask & sigmask(SIGTTIN)) ||
228 p->p_pgrp->pg_jobc == 0 ||
229 p->p_flag & P_PPWAIT)
230 return (EIO);
231 pgsignal(p->p_pgrp, SIGTTIN, 1);
232 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg",
233 0);
234 if (error)
235 return (error);
236 }
237 if (tp->t_canq.c_cc == 0) {
238 if (flag & IO_NDELAY)
239 return (EWOULDBLOCK);
240 error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
241 "ptsin", 0);
242 if (error)
243 return (error);
244 goto again;
245 }
246 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
247 if (ureadc(getc(&tp->t_canq), uio) < 0) {
248 error = EFAULT;
249 break;
250 }
251 if (tp->t_canq.c_cc == 1)
252 (void) getc(&tp->t_canq);
253 if (tp->t_canq.c_cc)
254 return (error);
255 } else
256 if (tp->t_oproc)
257 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
258 ptcwakeup(tp, FWRITE);
259 return (error);
260 }
261
262 /*
263 * Write to pseudo-tty.
264 * Wakeups of controlling tty will happen
265 * indirectly, when tty driver calls ptsstart.
266 */
267 static int
268 ptswrite(dev, uio, flag)
269 dev_t dev;
270 struct uio *uio;
271 int flag;
272 {
273 register struct tty *tp;
274
275 tp = &pt_tty[minor(dev)];
276 if (tp->t_oproc == 0)
277 return (EIO);
278 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
279 }
280
281 /*
282 * Start output on pseudo-tty.
283 * Wake up process selecting or sleeping for input from controlling tty.
284 */
285 static void
286 ptsstart(tp)
287 struct tty *tp;
288 {
289 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
290
291 if (tp->t_state & TS_TTSTOP)
292 return;
293 if (pti->pt_flags & PF_STOPPED) {
294 pti->pt_flags &= ~PF_STOPPED;
295 pti->pt_send = TIOCPKT_START;
296 }
297 ptcwakeup(tp, FREAD);
298 }
299
300 static void
301 ptcwakeup(tp, flag)
302 struct tty *tp;
303 int flag;
304 {
305 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
306
307 if (flag & FREAD) {
308 selwakeup(&pti->pt_selr);
309 wakeup(TSA_PTC_READ(tp));
310 }
311 if (flag & FWRITE) {
312 selwakeup(&pti->pt_selw);
313 wakeup(TSA_PTC_WRITE(tp));
314 }
315 }
316
317 static int
318 ptcopen(dev, flag, devtype, p)
319 dev_t dev;
320 int flag, devtype;
321 struct proc *p;
322 {
323 register struct tty *tp;
324 struct pt_ioctl *pti;
325
326 if (minor(dev) >= npty)
327 return (ENXIO);
328 tp = &pt_tty[minor(dev)];
329 if (tp->t_oproc)
330 return (EIO);
331 tp->t_oproc = ptsstart;
332 #ifdef sun4c
333 tp->t_stop = ptsstop;
334 #endif
335 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
336 tp->t_lflag &= ~EXTPROC;
337 pti = &pt_ioctl[minor(dev)];
338 pti->pt_flags = 0;
339 pti->pt_send = 0;
340 pti->pt_ucntl = 0;
341 return (0);
342 }
343
344 static int
345 ptcclose(dev, flags, fmt, p)
346 dev_t dev;
347 int flags;
348 int fmt;
349 struct proc *p;
350 {
351 register struct tty *tp;
352
353 tp = &pt_tty[minor(dev)];
354 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
355
356 /*
357 * XXX MDMBUF makes no sense for ptys but would inhibit the above
358 * l_modem(). CLOCAL makes sense but isn't supported. Special
359 * l_modem()s that ignore carrier drop make no sense for ptys but
360 * may be in use because other parts of the line discipline make
361 * sense for ptys. Recover by doing everything that a normal
362 * ttymodem() would have done except for sending a SIGHUP.
363 */
364 if (tp->t_state & TS_ISOPEN) {
365 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
366 tp->t_state |= TS_ZOMBIE;
367 ttyflush(tp, FREAD | FWRITE);
368 }
369
370 tp->t_oproc = 0; /* mark closed */
371 return (0);
372 }
373
374 static int
375 ptcread(dev, uio, flag)
376 dev_t dev;
377 struct uio *uio;
378 int flag;
379 {
380 register struct tty *tp = &pt_tty[minor(dev)];
381 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
382 char buf[BUFSIZ];
383 int error = 0, cc;
384
385 /*
386 * We want to block until the slave
387 * is open, and there's something to read;
388 * but if we lost the slave or we're NBIO,
389 * then return the appropriate error instead.
390 */
391 for (;;) {
392 if (tp->t_state&TS_ISOPEN) {
393 if (pti->pt_flags&PF_PKT && pti->pt_send) {
394 error = ureadc((int)pti->pt_send, uio);
395 if (error)
396 return (error);
397 if (pti->pt_send & TIOCPKT_IOCTL) {
398 cc = min(uio->uio_resid,
399 sizeof(tp->t_termios));
400 uiomove((caddr_t)&tp->t_termios, cc,
401 uio);
402 }
403 pti->pt_send = 0;
404 return (0);
405 }
406 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
407 error = ureadc((int)pti->pt_ucntl, uio);
408 if (error)
409 return (error);
410 pti->pt_ucntl = 0;
411 return (0);
412 }
413 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
414 break;
415 }
416 if ((tp->t_state & TS_CONNECTED) == 0)
417 return (0); /* EOF */
418 if (flag & IO_NDELAY)
419 return (EWOULDBLOCK);
420 error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
421 if (error)
422 return (error);
423 }
424 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
425 error = ureadc(0, uio);
426 while (uio->uio_resid > 0 && error == 0) {
427 cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
428 if (cc <= 0)
429 break;
430 error = uiomove(buf, cc, uio);
431 }
432 ttwwakeup(tp);
433 return (error);
434 }
435
436 static void
437 ptsstop(tp, flush)
438 register struct tty *tp;
439 int flush;
440 {
441 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
442 int flag;
443
444 /* note: FLUSHREAD and FLUSHWRITE already ok */
445 if (flush == 0) {
446 flush = TIOCPKT_STOP;
447 pti->pt_flags |= PF_STOPPED;
448 } else
449 pti->pt_flags &= ~PF_STOPPED;
450 pti->pt_send |= flush;
451 /* change of perspective */
452 flag = 0;
453 if (flush & FREAD)
454 flag |= FWRITE;
455 if (flush & FWRITE)
456 flag |= FREAD;
457 ptcwakeup(tp, flag);
458 }
459
460 static int
461 ptcselect(dev, rw, p)
462 dev_t dev;
463 int rw;
464 struct proc *p;
465 {
466 register struct tty *tp = &pt_tty[minor(dev)];
467 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
468 int s;
469
470 if ((tp->t_state & TS_CONNECTED) == 0)
471 return (1);
472 switch (rw) {
473
474 case FREAD:
475 /*
476 * Need to block timeouts (ttrstart).
477 */
478 s = spltty();
479 if ((tp->t_state&TS_ISOPEN) &&
480 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
481 splx(s);
482 return (1);
483 }
484 splx(s);
485 /* FALLTHROUGH */
486
487 case 0: /* exceptional */
488 if ((tp->t_state&TS_ISOPEN) &&
489 ((pti->pt_flags&PF_PKT && pti->pt_send) ||
490 (pti->pt_flags&PF_UCNTL && pti->pt_ucntl)))
491 return (1);
492 selrecord(p, &pti->pt_selr);
493 break;
494
495
496 case FWRITE:
497 if (tp->t_state&TS_ISOPEN) {
498 if (pti->pt_flags & PF_REMOTE) {
499 if (tp->t_canq.c_cc == 0)
500 return (1);
501 } else {
502 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
503 return (1);
504 if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
505 return (1);
506 }
507 }
508 selrecord(p, &pti->pt_selw);
509 break;
510
511 }
512 return (0);
513 }
514
515 static int
516 ptcwrite(dev, uio, flag)
517 dev_t dev;
518 register struct uio *uio;
519 int flag;
520 {
521 register struct tty *tp = &pt_tty[minor(dev)];
522 register u_char *cp = 0;
523 register int cc = 0;
524 u_char locbuf[BUFSIZ];
525 int cnt = 0;
526 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
527 int error = 0;
528
529 again:
530 if ((tp->t_state&TS_ISOPEN) == 0)
531 goto block;
532 if (pti->pt_flags & PF_REMOTE) {
533 if (tp->t_canq.c_cc)
534 goto block;
535 while ((uio->uio_resid > 0 || cc > 0) &&
536 tp->t_canq.c_cc < TTYHOG - 1) {
537 if (cc == 0) {
538 cc = min(uio->uio_resid, BUFSIZ);
539 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
540 cp = locbuf;
541 error = uiomove((caddr_t)cp, cc, uio);
542 if (error)
543 return (error);
544 /* check again for safety */
545 if ((tp->t_state & TS_ISOPEN) == 0) {
546 /* adjust as usual */
547 uio->uio_resid += cc;
548 return (EIO);
549 }
550 }
551 if (cc > 0) {
552 cc = b_to_q((char *)cp, cc, &tp->t_canq);
553 /*
554 * XXX we don't guarantee that the canq size
555 * is >= TTYHOG, so the above b_to_q() may
556 * leave some bytes uncopied. However, space
557 * is guaranteed for the null terminator if
558 * we don't fail here since (TTYHOG - 1) is
559 * not a multiple of CBSIZE.
560 */
561 if (cc > 0)
562 break;
563 }
564 }
565 /* adjust for data copied in but not written */
566 uio->uio_resid += cc;
567 (void) putc(0, &tp->t_canq);
568 ttwakeup(tp);
569 wakeup(TSA_PTS_READ(tp));
570 return (0);
571 }
572 while (uio->uio_resid > 0 || cc > 0) {
573 if (cc == 0) {
574 cc = min(uio->uio_resid, BUFSIZ);
575 cp = locbuf;
576 error = uiomove((caddr_t)cp, cc, uio);
577 if (error)
578 return (error);
579 /* check again for safety */
580 if ((tp->t_state & TS_ISOPEN) == 0) {
581 /* adjust for data copied in but not written */
582 uio->uio_resid += cc;
583 return (EIO);
584 }
585 }
586 while (cc > 0) {
587 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
588 (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
589 wakeup(TSA_HUP_OR_INPUT(tp));
590 goto block;
591 }
592 (*linesw[tp->t_line].l_rint)(*cp++, tp);
593 cnt++;
594 cc--;
595 }
596 cc = 0;
597 }
598 return (0);
599 block:
600 /*
601 * Come here to wait for slave to open, for space
602 * in outq, or space in rawq, or an empty canq.
603 */
604 if ((tp->t_state & TS_CONNECTED) == 0) {
605 /* adjust for data copied in but not written */
606 uio->uio_resid += cc;
607 return (EIO);
608 }
609 if (flag & IO_NDELAY) {
610 /* adjust for data copied in but not written */
611 uio->uio_resid += cc;
612 if (cnt == 0)
613 return (EWOULDBLOCK);
614 return (0);
615 }
616 error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
617 if (error) {
618 /* adjust for data copied in but not written */
619 uio->uio_resid += cc;
620 return (error);
621 }
622 goto again;
623 }
624
625 static struct tty *
626 ptydevtotty(dev)
627 dev_t dev;
628 {
629 if (minor(dev) >= npty)
630 return (NULL);
631
632 return &pt_tty[minor(dev)];
633 }
634
635 /*ARGSUSED*/
636 static int
637 ptyioctl(dev, cmd, data, flag, p)
638 dev_t dev;
639 int cmd;
640 caddr_t data;
641 int flag;
642 struct proc *p;
643 {
644 register struct tty *tp = &pt_tty[minor(dev)];
645 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
646 register u_char *cc = tp->t_cc;
647 int stop, error;
648
649 /*
650 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
651 * ttywflush(tp) will hang if there are characters in the outq.
652 */
653 if (cmd == TIOCEXT) {
654 /*
655 * When the EXTPROC bit is being toggled, we need
656 * to send an TIOCPKT_IOCTL if the packet driver
657 * is turned on.
658 */
659 if (*(int *)data) {
660 if (pti->pt_flags & PF_PKT) {
661 pti->pt_send |= TIOCPKT_IOCTL;
662 ptcwakeup(tp, FREAD);
663 }
664 tp->t_lflag |= EXTPROC;
665 } else {
666 if ((tp->t_lflag & EXTPROC) &&
667 (pti->pt_flags & PF_PKT)) {
668 pti->pt_send |= TIOCPKT_IOCTL;
669 ptcwakeup(tp, FREAD);
670 }
671 tp->t_lflag &= ~EXTPROC;
672 }
673 return(0);
674 } else
675 if (cdevsw[major(dev)]->d_open == ptcopen)
676 switch (cmd) {
677
678 case TIOCGPGRP:
679 /*
680 * We aviod calling ttioctl on the controller since,
681 * in that case, tp must be the controlling terminal.
682 */
683 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
684 return (0);
685
686 case TIOCPKT:
687 if (*(int *)data) {
688 if (pti->pt_flags & PF_UCNTL)
689 return (EINVAL);
690 pti->pt_flags |= PF_PKT;
691 } else
692 pti->pt_flags &= ~PF_PKT;
693 return (0);
694
695 case TIOCUCNTL:
696 if (*(int *)data) {
697 if (pti->pt_flags & PF_PKT)
698 return (EINVAL);
699 pti->pt_flags |= PF_UCNTL;
700 } else
701 pti->pt_flags &= ~PF_UCNTL;
702 return (0);
703
704 case TIOCREMOTE:
705 if (*(int *)data)
706 pti->pt_flags |= PF_REMOTE;
707 else
708 pti->pt_flags &= ~PF_REMOTE;
709 ttyflush(tp, FREAD|FWRITE);
710 return (0);
711
712 #ifdef COMPAT_43
713 case TIOCSETP:
714 case TIOCSETN:
715 #endif
716 case TIOCSETD:
717 case TIOCSETA:
718 case TIOCSETAW:
719 case TIOCSETAF:
720 ndflush(&tp->t_outq, tp->t_outq.c_cc);
721 break;
722
723 case TIOCSIG:
724 if (*(unsigned int *)data >= NSIG ||
725 *(unsigned int *)data == 0)
726 return(EINVAL);
727 if ((tp->t_lflag&NOFLSH) == 0)
728 ttyflush(tp, FREAD|FWRITE);
729 pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
730 if ((*(unsigned int *)data == SIGINFO) &&
731 ((tp->t_lflag&NOKERNINFO) == 0))
732 ttyinfo(tp);
733 return(0);
734 }
735 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
736 if (error < 0)
737 error = ttioctl(tp, cmd, data, flag);
738 if (error < 0) {
739 if (pti->pt_flags & PF_UCNTL &&
740 (cmd & ~0xff) == UIOCCMD(0)) {
741 if (cmd & 0xff) {
742 pti->pt_ucntl = (u_char)cmd;
743 ptcwakeup(tp, FREAD);
744 }
745 return (0);
746 }
747 error = ENOTTY;
748 }
749 /*
750 * If external processing and packet mode send ioctl packet.
751 */
752 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
753 switch(cmd) {
754 case TIOCSETA:
755 case TIOCSETAW:
756 case TIOCSETAF:
757 #ifdef COMPAT_43
758 case TIOCSETP:
759 case TIOCSETN:
760 #endif
761 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
762 case TIOCSETC:
763 case TIOCSLTC:
764 case TIOCLBIS:
765 case TIOCLBIC:
766 case TIOCLSET:
767 #endif
768 pti->pt_send |= TIOCPKT_IOCTL;
769 ptcwakeup(tp, FREAD);
770 default:
771 break;
772 }
773 }
774 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
775 && CCEQ(cc[VSTART], CTRL('q'));
776 if (pti->pt_flags & PF_NOSTOP) {
777 if (stop) {
778 pti->pt_send &= ~TIOCPKT_NOSTOP;
779 pti->pt_send |= TIOCPKT_DOSTOP;
780 pti->pt_flags &= ~PF_NOSTOP;
781 ptcwakeup(tp, FREAD);
782 }
783 } else {
784 if (!stop) {
785 pti->pt_send &= ~TIOCPKT_DOSTOP;
786 pti->pt_send |= TIOCPKT_NOSTOP;
787 pti->pt_flags |= PF_NOSTOP;
788 ptcwakeup(tp, FREAD);
789 }
790 }
791 return (error);
792 }
793
794 static ptc_devsw_installed = 0;
795
796 static void
797 ptc_drvinit(void *unused)
798 {
799 #ifdef DEVFS
800 int i,j,k;
801 #endif
802 dev_t dev;
803
804 if( ! ptc_devsw_installed ) {
805 dev = makedev(CDEV_MAJOR_S, 0);
806 cdevsw_add(&dev, &pts_cdevsw, NULL);
807 dev = makedev(CDEV_MAJOR_C, 0);
808 cdevsw_add(&dev, &ptc_cdevsw, NULL);
809 ptc_devsw_installed = 1;
810 #ifdef DEVFS
811 for ( i = 0 ; i<NPTY ; i++ ) {
812 j = i / 32;
813 k = i % 32;
814 devfs_token_pts[i] =
815 devfs_add_devswf(&pts_cdevsw,i,
816 DV_CHR,0,0,0666,
817 "tty%c%n",jnames[j],k);
818 devfs_token_ptc[i] =
819 devfs_add_devswf(&ptc_cdevsw,i,
820 DV_CHR,0,0,0666,
821 "pty%c%n",jnames[j],k);
822 }
823 #endif
824 }
825 }
826
827 SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
Cache object: 38c86be03d7fdcd0603aa9fa75e3981e
|