The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_pty.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e1f0ff9a87f7d6d47429cb38c5db09d2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.