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