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