]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/tty_pty.c
Move the old BSD4.3 tty compatibility from (!BURN_BRIDGES && COMPAT_43)
[FreeBSD/FreeBSD.git] / 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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      @(#)tty_pty.c   8.4 (Berkeley) 2/20/95
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 /*
36  * Pseudo-teletype Driver
37  * (Actually two drivers, requiring two entries in 'cdevsw')
38  */
39 #include "opt_compat.h"
40 #include "opt_tty.h"
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/sx.h>
46 #if defined(COMPAT_43TTY)
47 #include <sys/ioctl_compat.h>
48 #endif
49 #include <sys/proc.h>
50 #include <sys/tty.h>
51 #include <sys/conf.h>
52 #include <sys/fcntl.h>
53 #include <sys/poll.h>
54 #include <sys/kernel.h>
55 #include <sys/uio.h>
56 #include <sys/signalvar.h>
57 #include <sys/malloc.h>
58
59 static MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
60
61 static void ptsstart(struct tty *tp);
62 static void ptsstop(struct tty *tp, int rw);
63 static void ptcwakeup(struct tty *tp, int flag);
64 static struct cdev *ptyinit(struct cdev *cdev, struct thread *td);
65
66 static  d_open_t        ptsopen;
67 static  d_close_t       ptsclose;
68 static  d_read_t        ptsread;
69 static  d_write_t       ptswrite;
70 static  d_ioctl_t       ptsioctl;
71 static  d_open_t        ptcopen;
72 static  d_close_t       ptcclose;
73 static  d_read_t        ptcread;
74 static  d_ioctl_t       ptcioctl;
75 static  d_write_t       ptcwrite;
76 static  d_poll_t        ptcpoll;
77
78 static struct cdevsw pts_cdevsw = {
79         .d_version =    D_VERSION,
80         .d_open =       ptsopen,
81         .d_close =      ptsclose,
82         .d_read =       ptsread,
83         .d_write =      ptswrite,
84         .d_ioctl =      ptsioctl,
85         .d_name =       "pts",
86         .d_flags =      D_TTY | D_NEEDGIANT,
87 };
88
89 static struct cdevsw ptc_cdevsw = {
90         .d_version =    D_VERSION,
91         .d_open =       ptcopen,
92         .d_close =      ptcclose,
93         .d_read =       ptcread,
94         .d_write =      ptcwrite,
95         .d_ioctl =      ptcioctl,
96         .d_poll =       ptcpoll,
97         .d_name =       "ptc",
98         .d_flags =      D_TTY | D_NEEDGIANT,
99 };
100
101 #define BUFSIZ 100              /* Chunk size iomoved to/from user */
102
103 struct  ptsc {
104         int     pt_flags;
105         struct  selinfo pt_selr, pt_selw;
106         u_char  pt_send;
107         u_char  pt_ucntl;
108         struct tty *pt_tty;
109         struct cdev *devs, *devc;
110         struct  prison *pt_prison;
111 };
112
113 #define PF_PKT          0x08            /* packet mode */
114 #define PF_STOPPED      0x10            /* user told stopped */
115 #define PF_NOSTOP       0x40
116 #define PF_UCNTL        0x80            /* user control mode */
117
118 #define TSA_PTC_READ(tp)        ((void *)&(tp)->t_outq.c_cf)
119 #define TSA_PTC_WRITE(tp)       ((void *)&(tp)->t_rawq.c_cl)
120 #define TSA_PTS_READ(tp)        ((void *)&(tp)->t_canq)
121
122 static char *names = "pqrsPQRS";
123 /*
124  * This function creates and initializes a pts/ptc pair
125  *
126  * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
127  * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
128  *
129  * XXX: define and add mapping of upper minor bits to allow more
130  *      than 256 ptys.
131  */
132 static struct cdev *
133 ptyinit(struct cdev *devc, struct thread *td)
134 {
135         struct cdev *devs;
136         struct ptsc *pt;
137         int n;
138
139         n = minor(devc);
140         /* For now we only map the lower 8 bits of the minor */
141         if (n & ~0xff)
142                 return (NULL);
143
144         devc->si_flags &= ~SI_CHEAPCLONE;
145
146         pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
147         pt->devs = devs = make_dev_cred(&pts_cdevsw, n, td->td_ucred,
148             UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32);
149         pt->devc = devc;
150
151         pt->pt_tty = ttyalloc();
152         pt->pt_tty->t_sc = pt;
153         devs->si_drv1 = devc->si_drv1 = pt;
154         devs->si_tty = devc->si_tty = pt->pt_tty;
155         pt->pt_tty->t_dev = devs;
156         return (devc);
157 }
158
159 /*ARGSUSED*/
160 static  int
161 ptsopen(struct cdev *dev, int flag, int devtype, struct thread *td)
162 {
163         struct tty *tp;
164         int error;
165         struct ptsc *pt;
166
167         if (!dev->si_drv1)
168                 return(ENXIO);
169         pt = dev->si_drv1;
170         tp = dev->si_tty;
171         if ((tp->t_state & TS_ISOPEN) == 0) {
172                 ttyinitmode(tp, 1, 0);
173         } else if (tp->t_state & TS_XCLUDE && suser(td))
174                 return (EBUSY);
175         else if (pt->pt_prison != td->td_ucred->cr_prison)
176                 return (EBUSY);
177         if (tp->t_oproc)                        /* Ctrlr still around. */
178                 (void)ttyld_modem(tp, 1);
179         while ((tp->t_state & TS_CARR_ON) == 0) {
180                 if (flag&FNONBLOCK)
181                         break;
182                 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
183                                  "ptsopn", 0);
184                 if (error)
185                         return (error);
186         }
187         error = ttyld_open(tp, dev);
188         if (error == 0)
189                 ptcwakeup(tp, FREAD|FWRITE);
190         return (error);
191 }
192
193 static  int
194 ptsclose(struct cdev *dev, int flag, int mode, struct thread *td)
195 {
196         struct tty *tp;
197         int err;
198
199         tp = dev->si_tty;
200         err = ttyld_close(tp, flag);
201         (void) tty_close(tp);
202         return (err);
203 }
204
205 static  int
206 ptsread(struct cdev *dev, struct uio *uio, int flag)
207 {
208         struct tty *tp = dev->si_tty;
209         int error = 0;
210
211         if (tp->t_oproc)
212                 error = ttyld_read(tp, uio, flag);
213         ptcwakeup(tp, FWRITE);
214         return (error);
215 }
216
217 /*
218  * Write to pseudo-tty.
219  * Wakeups of controlling tty will happen
220  * indirectly, when tty driver calls ptsstart.
221  */
222 static  int
223 ptswrite(struct cdev *dev, struct uio *uio, int flag)
224 {
225         struct tty *tp;
226
227         tp = dev->si_tty;
228         if (tp->t_oproc == 0)
229                 return (EIO);
230         return (ttyld_write(tp, uio, flag));
231 }
232
233 /*
234  * Start output on pseudo-tty.
235  * Wake up process selecting or sleeping for input from controlling tty.
236  */
237 static void
238 ptsstart(struct tty *tp)
239 {
240         struct ptsc *pt = tp->t_sc;
241
242         if (tp->t_state & TS_TTSTOP)
243                 return;
244         if (pt->pt_flags & PF_STOPPED) {
245                 pt->pt_flags &= ~PF_STOPPED;
246                 pt->pt_send = TIOCPKT_START;
247         }
248         ptcwakeup(tp, FREAD);
249 }
250
251 static void
252 ptcwakeup(struct tty *tp, int flag)
253 {
254         struct ptsc *pt = tp->t_sc;
255
256         if (flag & FREAD) {
257                 selwakeuppri(&pt->pt_selr, TTIPRI);
258                 wakeup(TSA_PTC_READ(tp));
259         }
260         if (flag & FWRITE) {
261                 selwakeuppri(&pt->pt_selw, TTOPRI);
262                 wakeup(TSA_PTC_WRITE(tp));
263         }
264 }
265
266 static  int
267 ptcopen(struct cdev *dev, int flag, int devtype, struct thread *td)
268 {
269         struct tty *tp;
270         struct ptsc *pt;
271
272         if (!dev->si_drv1)
273                 ptyinit(dev, td);
274         if (!dev->si_drv1)
275                 return(ENXIO);
276         tp = dev->si_tty;
277         if (tp->t_oproc)
278                 return (EIO);
279         tp->t_timeout = -1;
280         tp->t_oproc = ptsstart;
281         tp->t_stop = ptsstop;
282         (void)ttyld_modem(tp, 1);
283         tp->t_lflag &= ~EXTPROC;
284         pt = dev->si_drv1;
285         pt->pt_prison = td->td_ucred->cr_prison;
286         pt->pt_flags = 0;
287         pt->pt_send = 0;
288         pt->pt_ucntl = 0;
289         return (0);
290 }
291
292 static  int
293 ptcclose(struct cdev *dev, int flags, int fmt, struct thread *td)
294 {
295         struct tty *tp;
296
297         tp = dev->si_tty;
298         (void)ttyld_modem(tp, 0);
299
300         /*
301          * XXX MDMBUF makes no sense for ptys but would inhibit the above
302          * l_modem().  CLOCAL makes sense but isn't supported.   Special
303          * l_modem()s that ignore carrier drop make no sense for ptys but
304          * may be in use because other parts of the line discipline make
305          * sense for ptys.  Recover by doing everything that a normal
306          * ttymodem() would have done except for sending a SIGHUP.
307          */
308         if (tp->t_state & TS_ISOPEN) {
309                 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
310                 tp->t_state |= TS_ZOMBIE;
311                 ttyflush(tp, FREAD | FWRITE);
312         }
313
314         tp->t_oproc = 0;                /* mark closed */
315         return (0);
316 }
317
318 static  int
319 ptcread(struct cdev *dev, struct uio *uio, int flag)
320 {
321         struct tty *tp = dev->si_tty;
322         struct ptsc *pt = dev->si_drv1;
323         char buf[BUFSIZ];
324         int error = 0, cc;
325
326         /*
327          * We want to block until the slave
328          * is open, and there's something to read;
329          * but if we lost the slave or we're NBIO,
330          * then return the appropriate error instead.
331          */
332         for (;;) {
333                 if (tp->t_state&TS_ISOPEN) {
334                         if (pt->pt_flags&PF_PKT && pt->pt_send) {
335                                 error = ureadc((int)pt->pt_send, uio);
336                                 if (error)
337                                         return (error);
338                                 if (pt->pt_send & TIOCPKT_IOCTL) {
339                                         cc = min(uio->uio_resid,
340                                                 sizeof(tp->t_termios));
341                                         uiomove(&tp->t_termios, cc, uio);
342                                 }
343                                 pt->pt_send = 0;
344                                 return (0);
345                         }
346                         if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) {
347                                 error = ureadc((int)pt->pt_ucntl, uio);
348                                 if (error)
349                                         return (error);
350                                 pt->pt_ucntl = 0;
351                                 return (0);
352                         }
353                         if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
354                                 break;
355                 }
356                 if ((tp->t_state & TS_CONNECTED) == 0)
357                         return (0);     /* EOF */
358                 if (flag & O_NONBLOCK)
359                         return (EWOULDBLOCK);
360                 error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
361                 if (error)
362                         return (error);
363         }
364         if (pt->pt_flags & (PF_PKT|PF_UCNTL))
365                 error = ureadc(0, uio);
366         while (uio->uio_resid > 0 && error == 0) {
367                 cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
368                 if (cc <= 0)
369                         break;
370                 error = uiomove(buf, cc, uio);
371         }
372         ttwwakeup(tp);
373         return (error);
374 }
375
376 static  void
377 ptsstop(struct tty *tp, int flush)
378 {
379         struct ptsc *pt = tp->t_sc;
380         int flag;
381
382         /* note: FLUSHREAD and FLUSHWRITE already ok */
383         if (flush == 0) {
384                 flush = TIOCPKT_STOP;
385                 pt->pt_flags |= PF_STOPPED;
386         } else
387                 pt->pt_flags &= ~PF_STOPPED;
388         pt->pt_send |= flush;
389         /* change of perspective */
390         flag = 0;
391         if (flush & FREAD)
392                 flag |= FWRITE;
393         if (flush & FWRITE)
394                 flag |= FREAD;
395         ptcwakeup(tp, flag);
396 }
397
398 static  int
399 ptcpoll(struct cdev *dev, int events, struct thread *td)
400 {
401         struct tty *tp = dev->si_tty;
402         struct ptsc *pt = dev->si_drv1;
403         int revents = 0;
404         int s;
405
406         if ((tp->t_state & TS_CONNECTED) == 0)
407                 return (events & 
408                    (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM));
409
410         /*
411          * Need to block timeouts (ttrstart).
412          */
413         s = spltty();
414
415         if (events & (POLLIN | POLLRDNORM))
416                 if ((tp->t_state & TS_ISOPEN) &&
417                     ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
418                      ((pt->pt_flags & PF_PKT) && pt->pt_send) ||
419                      ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl)))
420                         revents |= events & (POLLIN | POLLRDNORM);
421
422         if (events & (POLLOUT | POLLWRNORM))
423                 if (tp->t_state & TS_ISOPEN &&
424                     (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
425                       (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
426                         revents |= events & (POLLOUT | POLLWRNORM);
427
428         if (events & POLLHUP)
429                 if ((tp->t_state & TS_CARR_ON) == 0)
430                         revents |= POLLHUP;
431
432         if (revents == 0) {
433                 if (events & (POLLIN | POLLRDNORM))
434                         selrecord(td, &pt->pt_selr);
435
436                 if (events & (POLLOUT | POLLWRNORM))
437                         selrecord(td, &pt->pt_selw);
438         }
439         splx(s);
440
441         return (revents);
442 }
443
444 static  int
445 ptcwrite(struct cdev *dev, struct uio *uio, int flag)
446 {
447         struct tty *tp = dev->si_tty;
448         u_char *cp = 0;
449         int cc = 0;
450         u_char locbuf[BUFSIZ];
451         int cnt = 0;
452         int error = 0;
453
454 again:
455         if ((tp->t_state&TS_ISOPEN) == 0)
456                 goto block;
457         while (uio->uio_resid > 0 || cc > 0) {
458                 if (cc == 0) {
459                         cc = min(uio->uio_resid, BUFSIZ);
460                         cp = locbuf;
461                         error = uiomove(cp, cc, uio);
462                         if (error)
463                                 return (error);
464                         /* check again for safety */
465                         if ((tp->t_state & TS_ISOPEN) == 0) {
466                                 /* adjust for data copied in but not written */
467                                 uio->uio_resid += cc;
468                                 return (EIO);
469                         }
470                 }
471                 while (cc > 0) {
472                         if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
473                            (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
474                                 wakeup(TSA_HUP_OR_INPUT(tp));
475                                 goto block;
476                         }
477                         ttyld_rint(tp, *cp++);
478                         cnt++;
479                         cc--;
480                 }
481                 cc = 0;
482         }
483         return (0);
484 block:
485         /*
486          * Come here to wait for slave to open, for space
487          * in outq, or space in rawq, or an empty canq.
488          */
489         if ((tp->t_state & TS_CONNECTED) == 0) {
490                 /* adjust for data copied in but not written */
491                 uio->uio_resid += cc;
492                 return (EIO);
493         }
494         if (flag & O_NONBLOCK) {
495                 /* adjust for data copied in but not written */
496                 uio->uio_resid += cc;
497                 if (cnt == 0)
498                         return (EWOULDBLOCK);
499                 return (0);
500         }
501         error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
502         if (error) {
503                 /* adjust for data copied in but not written */
504                 uio->uio_resid += cc;
505                 return (error);
506         }
507         goto again;
508 }
509
510 /*ARGSUSED*/
511 static  int
512 ptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
513 {
514         struct tty *tp = dev->si_tty;
515         struct ptsc *pt = dev->si_drv1;
516
517         switch (cmd) {
518
519         case TIOCGPGRP:
520                 /*
521                  * We avoid calling ttioctl on the controller since,
522                  * in that case, tp must be the controlling terminal.
523                  */
524                 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
525                 return (0);
526
527         case TIOCPKT:
528                 if (*(int *)data) {
529                         if (pt->pt_flags & PF_UCNTL)
530                                 return (EINVAL);
531                         pt->pt_flags |= PF_PKT;
532                 } else
533                         pt->pt_flags &= ~PF_PKT;
534                 return (0);
535
536         case TIOCUCNTL:
537                 if (*(int *)data) {
538                         if (pt->pt_flags & PF_PKT)
539                                 return (EINVAL);
540                         pt->pt_flags |= PF_UCNTL;
541                 } else
542                         pt->pt_flags &= ~PF_UCNTL;
543                 return (0);
544         }
545
546         /*
547          * The rest of the ioctls shouldn't be called until
548          * the slave is open.
549          */
550         if ((tp->t_state & TS_ISOPEN) == 0)
551                 return (EAGAIN);
552
553         switch (cmd) {
554 #ifdef COMPAT_43TTY
555         case TIOCSETP:
556         case TIOCSETN:
557 #endif
558         case TIOCSETD:
559         case TIOCSETA:
560         case TIOCSETAW:
561         case TIOCSETAF:
562                 /*
563                  * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
564                  * ttywflush(tp) will hang if there are characters in
565                  * the outq.
566                  */
567                 ndflush(&tp->t_outq, tp->t_outq.c_cc);
568                 break;
569
570         case TIOCSIG:
571                 if (*(unsigned int *)data >= NSIG ||
572                     *(unsigned int *)data == 0)
573                         return(EINVAL);
574                 if ((tp->t_lflag&NOFLSH) == 0)
575                         ttyflush(tp, FREAD|FWRITE);
576                 if (tp->t_pgrp != NULL) {
577                         PGRP_LOCK(tp->t_pgrp);
578                         pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
579                         PGRP_UNLOCK(tp->t_pgrp);
580                 }
581                 if ((*(unsigned int *)data == SIGINFO) &&
582                     ((tp->t_lflag&NOKERNINFO) == 0))
583                         ttyinfo(tp);
584                 return(0);
585         }
586
587         return (ptsioctl(dev, cmd, data, flag, td));
588 }
589
590 /*ARGSUSED*/
591 static  int
592 ptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
593 {
594         struct tty *tp = dev->si_tty;
595         struct ptsc *pt = dev->si_drv1;
596         u_char *cc = tp->t_cc;
597         int stop, error;
598
599         if (cmd == TIOCEXT) {
600                 /*
601                  * When the EXTPROC bit is being toggled, we need
602                  * to send an TIOCPKT_IOCTL if the packet driver
603                  * is turned on.
604                  */
605                 if (*(int *)data) {
606                         if (pt->pt_flags & PF_PKT) {
607                                 pt->pt_send |= TIOCPKT_IOCTL;
608                                 ptcwakeup(tp, FREAD);
609                         }
610                         tp->t_lflag |= EXTPROC;
611                 } else {
612                         if ((tp->t_lflag & EXTPROC) &&
613                             (pt->pt_flags & PF_PKT)) {
614                                 pt->pt_send |= TIOCPKT_IOCTL;
615                                 ptcwakeup(tp, FREAD);
616                         }
617                         tp->t_lflag &= ~EXTPROC;
618                 }
619                 return(0);
620         }
621         error = ttyioctl(dev, cmd, data, flag, td);
622         if (error == ENOTTY) {
623                 if (pt->pt_flags & PF_UCNTL &&
624                     (cmd & ~0xff) == UIOCCMD(0)) {
625                         if (cmd & 0xff) {
626                                 pt->pt_ucntl = (u_char)cmd;
627                                 ptcwakeup(tp, FREAD);
628                         }
629                         return (0);
630                 }
631                 error = ENOTTY;
632         }
633         /*
634          * If external processing and packet mode send ioctl packet.
635          */
636         if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) {
637                 switch(cmd) {
638                 case TIOCSETA:
639                 case TIOCSETAW:
640                 case TIOCSETAF:
641 #ifdef COMPAT_43TTY
642                 case TIOCSETP:
643                 case TIOCSETN:
644                 case TIOCSETC:
645                 case TIOCSLTC:
646                 case TIOCLBIS:
647                 case TIOCLBIC:
648                 case TIOCLSET:
649 #endif
650                         pt->pt_send |= TIOCPKT_IOCTL;
651                         ptcwakeup(tp, FREAD);
652                         break;
653                 default:
654                         break;
655                 }
656         }
657         stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
658                 && CCEQ(cc[VSTART], CTRL('q'));
659         if (pt->pt_flags & PF_NOSTOP) {
660                 if (stop) {
661                         pt->pt_send &= ~TIOCPKT_NOSTOP;
662                         pt->pt_send |= TIOCPKT_DOSTOP;
663                         pt->pt_flags &= ~PF_NOSTOP;
664                         ptcwakeup(tp, FREAD);
665                 }
666         } else {
667                 if (!stop) {
668                         pt->pt_send &= ~TIOCPKT_DOSTOP;
669                         pt->pt_send |= TIOCPKT_NOSTOP;
670                         pt->pt_flags |= PF_NOSTOP;
671                         ptcwakeup(tp, FREAD);
672                 }
673         }
674         return (error);
675 }
676
677 static void
678 pty_clone(void *arg, struct ucred *cr, char *name, int namelen,
679     struct cdev **dev)
680 {
681         int u;
682
683         if (*dev != NULL)
684                 return;
685         if (bcmp(name, "pty", 3) != 0)
686                 return;
687         if (name[5] != '\0')
688                 return;
689         switch (name[3]) {
690         case 'p': u =   0; break;
691         case 'q': u =  32; break;
692         case 'r': u =  64; break;
693         case 's': u =  96; break;
694         case 'P': u = 128; break;
695         case 'Q': u = 160; break;
696         case 'R': u = 192; break;
697         case 'S': u = 224; break;
698         default: return;
699         }
700         if (name[4] >= '0' && name[4] <= '9')
701                 u += name[4] - '0';
702         else if (name[4] >= 'a' && name[4] <= 'v')
703                 u += name[4] - 'a' + 10;
704         else
705                 return;
706         *dev = make_dev_cred(&ptc_cdevsw, u, cr,
707             UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32);
708         dev_ref(*dev);
709         (*dev)->si_flags |= SI_CHEAPCLONE;
710         return;
711 }
712
713 static void
714 ptc_drvinit(void *unused)
715 {
716
717         EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000);
718 }
719
720 SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,ptc_drvinit,NULL)