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 --- 17 unchanged lines hidden (view full) --- 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 * $Id: tty_pty.c,v 1.61 1999/05/31 11:27:38 phk Exp $ |
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 44#include <sys/param.h> 45#include <sys/systm.h> 46#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 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/vnode.h> 56#include <sys/signalvar.h> |
57#include <sys/malloc.h> |
58 |
59MALLOC_DEFINE(M_PTY, "ptys", "pty data structures"); |
60 |
61static void ptsstart __P((struct tty *tp)); 62static void ptcwakeup __P((struct tty *tp, int flag)); |
63static void ptyinit __P((int n)); |
64 65static d_open_t ptsopen; 66static d_close_t ptsclose; 67static d_read_t ptsread; 68static d_write_t ptswrite; 69static d_ioctl_t ptyioctl; 70static d_stop_t ptsstop; 71static d_devtotty_t ptydevtotty; --- 44 unchanged lines hidden (view full) --- 116 /* maj */ CDEV_MAJOR_C, 117 /* dump */ nodump, 118 /* psize */ nopsize, 119 /* flags */ D_TTY, 120 /* maxio */ 0, 121 /* bmaj */ -1 122}; 123 |
124#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 125 |
126struct pt_ioctl { |
127 int pt_flags; 128 struct selinfo pt_selr, pt_selw; 129 u_char pt_send; 130 u_char pt_ucntl; |
131 struct tty pt_tty; 132}; |
133 134#define PF_PKT 0x08 /* packet mode */ 135#define PF_STOPPED 0x10 /* user told stopped */ 136#define PF_REMOTE 0x20 /* remote and flow controlled input */ 137#define PF_NOSTOP 0x40 138#define PF_UCNTL 0x80 /* user control mode */ 139 |
140/* |
141 * This function creates and initializes a pts/ptc pair |
142 * |
143 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 144 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 145 * 146 * XXX: define and add mapping of upper minor bits to allow more 147 * than 256 ptys. |
148 */ 149static void |
150ptyinit(n) |
151 int n; 152{ |
153 dev_t devs, devc; 154 char *names = "pqrsPQRS"; 155 struct pt_ioctl *pt; |
156 |
157 /* For now we only map the lower 8 bits of the minor */ 158 if (n & ~0xff) 159 return; 160 161 devs = make_dev(&pts_cdevsw, n, 162 0, 0, 0666, "tty%c%r", names[n / 32], n % 32); 163 devc = make_dev(&ptc_cdevsw, n, 164 0, 0, 0666, "pty%c%r", names[n / 32], n % 32); 165 166 pt = malloc(sizeof(*pt), M_PTY, M_WAITOK); 167 bzero(pt, sizeof(*pt)); 168 devs->si_drv1 = devc->si_drv1 = pt; 169 devs->si_tty_tty = devc->si_tty_tty = &pt->pt_tty; |
170} |
171 172/*ARGSUSED*/ 173static int 174ptsopen(dev, flag, devtype, p) 175 dev_t dev; 176 int flag, devtype; 177 struct proc *p; 178{ 179 register struct tty *tp; 180 int error; 181 |
182 if (!dev->si_drv1) 183 ptyinit(minor(dev)); 184 if (!dev->si_drv1) 185 return(ENXIO); 186 tp = dev->si_tty_tty; |
187 if ((tp->t_state & TS_ISOPEN) == 0) { 188 ttychars(tp); /* Set up default chars */ 189 tp->t_iflag = TTYDEF_IFLAG; 190 tp->t_oflag = TTYDEF_OFLAG; 191 tp->t_lflag = TTYDEF_LFLAG; 192 tp->t_cflag = TTYDEF_CFLAG; 193 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 194 } else if (tp->t_state & TS_XCLUDE && suser(p)) --- 18 unchanged lines hidden (view full) --- 213ptsclose(dev, flag, mode, p) 214 dev_t dev; 215 int flag, mode; 216 struct proc *p; 217{ 218 register struct tty *tp; 219 int err; 220 |
221 tp = dev->si_tty_tty; |
222 err = (*linesw[tp->t_line].l_close)(tp, flag); 223 ptsstop(tp, FREAD|FWRITE); 224 (void) ttyclose(tp); 225 return (err); 226} 227 228static int 229ptsread(dev, uio, flag) 230 dev_t dev; 231 struct uio *uio; 232 int flag; 233{ 234 struct proc *p = curproc; |
235 register struct tty *tp = dev->si_tty_tty; 236 register struct pt_ioctl *pti = dev->si_drv1; |
237 int error = 0; 238 239again: 240 if (pti->pt_flags & PF_REMOTE) { 241 while (isbackground(p, tp)) { 242 if ((p->p_sigignore & sigmask(SIGTTIN)) || 243 (p->p_sigmask & sigmask(SIGTTIN)) || 244 p->p_pgrp->pg_jobc == 0 || --- 38 unchanged lines hidden (view full) --- 283static int 284ptswrite(dev, uio, flag) 285 dev_t dev; 286 struct uio *uio; 287 int flag; 288{ 289 register struct tty *tp; 290 |
291 tp = dev->si_tty_tty; |
292 if (tp->t_oproc == 0) 293 return (EIO); 294 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 295} 296 297/* 298 * Start output on pseudo-tty. 299 * Wake up process selecting or sleeping for input from controlling tty. 300 */ 301static void 302ptsstart(tp) 303 struct tty *tp; 304{ |
305 register struct pt_ioctl *pti = tp->t_dev->si_drv1; |
306 307 if (tp->t_state & TS_TTSTOP) 308 return; 309 if (pti->pt_flags & PF_STOPPED) { 310 pti->pt_flags &= ~PF_STOPPED; 311 pti->pt_send = TIOCPKT_START; 312 } 313 ptcwakeup(tp, FREAD); 314} 315 316static void 317ptcwakeup(tp, flag) 318 struct tty *tp; 319 int flag; 320{ |
321 struct pt_ioctl *pti = tp->t_dev->si_drv1; |
322 323 if (flag & FREAD) { 324 selwakeup(&pti->pt_selr); 325 wakeup(TSA_PTC_READ(tp)); 326 } 327 if (flag & FWRITE) { 328 selwakeup(&pti->pt_selw); 329 wakeup(TSA_PTC_WRITE(tp)); --- 4 unchanged lines hidden (view full) --- 334ptcopen(dev, flag, devtype, p) 335 dev_t dev; 336 int flag, devtype; 337 struct proc *p; 338{ 339 register struct tty *tp; 340 struct pt_ioctl *pti; 341 |
342 if (!dev->si_drv1) 343 ptyinit(minor(dev)); 344 if (!dev->si_drv1) 345 return(ENXIO); 346 tp = dev->si_tty_tty; |
347 if (tp->t_oproc) 348 return (EIO); 349 tp->t_oproc = ptsstart; |
350 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 351 tp->t_lflag &= ~EXTPROC; |
352 pti = dev->si_drv1; |
353 pti->pt_flags = 0; 354 pti->pt_send = 0; 355 pti->pt_ucntl = 0; 356 return (0); 357} 358 359static int 360ptcclose(dev, flags, fmt, p) 361 dev_t dev; 362 int flags; 363 int fmt; 364 struct proc *p; 365{ 366 register struct tty *tp; 367 |
368 tp = dev->si_tty_tty; |
369 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 370 371 /* 372 * XXX MDMBUF makes no sense for ptys but would inhibit the above 373 * l_modem(). CLOCAL makes sense but isn't supported. Special 374 * l_modem()s that ignore carrier drop make no sense for ptys but 375 * may be in use because other parts of the line discipline make 376 * sense for ptys. Recover by doing everything that a normal --- 10 unchanged lines hidden (view full) --- 387} 388 389static int 390ptcread(dev, uio, flag) 391 dev_t dev; 392 struct uio *uio; 393 int flag; 394{ |
395 register struct tty *tp = dev->si_tty_tty; 396 struct pt_ioctl *pti = dev->si_drv1; |
397 char buf[BUFSIZ]; 398 int error = 0, cc; 399 400 /* 401 * We want to block until the slave 402 * is open, and there's something to read; 403 * but if we lost the slave or we're NBIO, 404 * then return the appropriate error instead. --- 43 unchanged lines hidden (view full) --- 448 return (error); 449} 450 451static void 452ptsstop(tp, flush) 453 register struct tty *tp; 454 int flush; 455{ |
456 struct pt_ioctl *pti = tp->t_dev->si_drv1; |
457 int flag; 458 459 /* note: FLUSHREAD and FLUSHWRITE already ok */ 460 if (flush == 0) { 461 flush = TIOCPKT_STOP; 462 pti->pt_flags |= PF_STOPPED; 463 } else 464 pti->pt_flags &= ~PF_STOPPED; --- 8 unchanged lines hidden (view full) --- 473} 474 475static int 476ptcpoll(dev, events, p) 477 dev_t dev; 478 int events; 479 struct proc *p; 480{ |
481 register struct tty *tp = dev->si_tty_tty; 482 struct pt_ioctl *pti = dev->si_drv1; |
483 int revents = 0; 484 int s; 485 486 if ((tp->t_state & TS_CONNECTED) == 0) 487 return (seltrue(dev, events, p) | POLLHUP); 488 489 /* 490 * Need to block timeouts (ttrstart). --- 32 unchanged lines hidden (view full) --- 523} 524 525static int 526ptcwrite(dev, uio, flag) 527 dev_t dev; 528 register struct uio *uio; 529 int flag; 530{ |
531 register struct tty *tp = dev->si_tty_tty; |
532 register u_char *cp = 0; 533 register int cc = 0; 534 u_char locbuf[BUFSIZ]; 535 int cnt = 0; |
536 struct pt_ioctl *pti = dev->si_drv1; |
537 int error = 0; 538 539again: 540 if ((tp->t_state&TS_ISOPEN) == 0) 541 goto block; 542 if (pti->pt_flags & PF_REMOTE) { 543 if (tp->t_canq.c_cc) 544 goto block; --- 86 unchanged lines hidden (view full) --- 631 } 632 goto again; 633} 634 635static struct tty * 636ptydevtotty(dev) 637 dev_t dev; 638{ |
639 if (minor(dev) & ~0xff) |
640 return (NULL); 641 |
642 return dev->si_tty_tty; |
643} 644 645/*ARGSUSED*/ 646static int 647ptyioctl(dev, cmd, data, flag, p) 648 dev_t dev; 649 u_long cmd; 650 caddr_t data; 651 int flag; 652 struct proc *p; 653{ |
654 register struct tty *tp = dev->si_tty_tty; 655 register struct pt_ioctl *pti = dev->si_drv1; |
656 register u_char *cc = tp->t_cc; 657 int stop, error; 658 659 if (devsw(dev)->d_open == ptcopen) { 660 switch (cmd) { 661 662 case TIOCGPGRP: 663 /* --- 143 unchanged lines hidden (view full) --- 807 pti->pt_send |= TIOCPKT_NOSTOP; 808 pti->pt_flags |= PF_NOSTOP; 809 ptcwakeup(tp, FREAD); 810 } 811 } 812 return (error); 813} 814 |
815 816static void ptc_drvinit __P((void *unused)); |
817 |
818static void 819ptc_drvinit(unused) 820 void *unused; 821{ |
822 static int ptc_devsw_installed; |
823 824 if( ! ptc_devsw_installed ) { 825 cdevsw_add(&pts_cdevsw); 826 cdevsw_add(&ptc_cdevsw); 827 ptc_devsw_installed = 1; |
828 } 829} 830 831SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL) |