nmdm.c revision 73166
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 3385052Sru * $FreeBSD: head/sys/dev/nmdm/nmdm.c 73166 2001-02-27 17:52:49Z julian $ 3450477Speter */ 351541Srgrimes 361541Srgrimes/* 372168Spaul * Pseudo-nulmodem Driver 382168Spaul */ 392168Spaul#include "opt_compat.h" 401541Srgrimes#include <sys/param.h> 411541Srgrimes#include <sys/systm.h> 428876Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 431541Srgrimes#include <sys/ioctl_compat.h> 441541Srgrimes#endif 451541Srgrimes#include <sys/proc.h> 461541Srgrimes#include <sys/tty.h> 471541Srgrimes#include <sys/conf.h> 481541Srgrimes#include <sys/fcntl.h> 491541Srgrimes#include <sys/poll.h> 501541Srgrimes#include <sys/kernel.h> 511541Srgrimes#include <sys/vnode.h> 521541Srgrimes#include <sys/signalvar.h> 531541Srgrimes#include <sys/malloc.h> 541541Srgrimes 551541SrgrimesMALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures"); 561541Srgrimes 571541Srgrimesstatic void nmdmstart __P((struct tty *tp)); 581541Srgrimesstatic void nmdmstop __P((struct tty *tp, int rw)); 591541Srgrimesstatic void wakeup_other __P((struct tty *tp, int flag)); 601541Srgrimesstatic void nmdminit __P((int n)); 611541Srgrimes 621541Srgrimesstatic d_open_t nmdmopen; 631541Srgrimesstatic d_close_t nmdmclose; 641541Srgrimesstatic d_read_t nmdmread; 651541Srgrimesstatic d_write_t nmdmwrite; 6613765Smppstatic d_ioctl_t nmdmioctl; 6713765Smpp 681541Srgrimes#define CDEV_MAJOR 18 691541Srgrimesstatic struct cdevsw nmdm_cdevsw = { 701541Srgrimes /* open */ nmdmopen, 711541Srgrimes /* close */ nmdmclose, 725791Swollman /* read */ nmdmread, 731541Srgrimes /* write */ nmdmwrite, 741541Srgrimes /* ioctl */ nmdmioctl, 751541Srgrimes /* poll */ ttypoll, 761541Srgrimes /* mmap */ nommap, 771541Srgrimes /* strategy */ nostrategy, 781541Srgrimes /* name */ "pts", 791541Srgrimes /* maj */ CDEV_MAJOR, 801541Srgrimes /* dump */ nodump, 811541Srgrimes /* psize */ nopsize, 821541Srgrimes /* flags */ D_TTY, 831541Srgrimes /* bmaj */ -1 845833Sbde}; 855833Sbde 865833Sbde#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 875833Sbde 885833Sbdestruct softpart { 891541Srgrimes struct tty nm_tty; 901541Srgrimes dev_t dev; 911541Srgrimes int modemsignals; /* bits defined in sys/ttycom.h */ 921541Srgrimes int gotbreak; 931541Srgrimes}; 941541Srgrimes 951541Srgrimesstruct nm_softc { 961541Srgrimes int pt_flags; 971541Srgrimes struct softpart part1, part2; 981541Srgrimes struct prison *pt_prison; 991541Srgrimes}; 1001541Srgrimes 1011541Srgrimes#define PF_STOPPED 0x10 /* user told stopped */ 1021541Srgrimes 1031541Srgrimesstatic void 10448381Smsmithnmdm_crossover(struct nm_softc *pti, 1057197Swollman struct softpart *ourpart, 1061541Srgrimes struct softpart *otherpart); 1071541Srgrimes 1081541Srgrimes#define GETPARTS(tp, ourpart, otherpart) \ 1091541Srgrimesdo { \ 1101541Srgrimes struct nm_softc *pti = tp->t_dev->si_drv1; \ 1111541Srgrimes if (tp == &pti->part1.nm_tty) { \ 11293084Sbde ourpart = &pti->part1; \ 11393084Sbde otherpart = &pti->part2; \ 1145791Swollman } else { \ 1155791Swollman ourpart = &pti->part2; \ 116120727Ssam otherpart = &pti->part1; \ 117120727Ssam } \ 118120727Ssam} while (0) 119120727Ssam 1201541Srgrimes/* 1211541Srgrimes * This function creates and initializes a pair of ttys. 1221541Srgrimes */ 1231541Srgrimesstatic void 1241541Srgrimesnmdminit(n) 1251541Srgrimes int n; 1261541Srgrimes{ 1271541Srgrimes dev_t dev1, dev2; 1281541Srgrimes struct nm_softc *pt; 1291541Srgrimes 1301541Srgrimes /* For now we only map the lower 8 bits of the minor */ 1311541Srgrimes if (n & ~0xff) 1321541Srgrimes return; 1331541Srgrimes 1341541Srgrimes pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK); 1351541Srgrimes bzero(pt, sizeof(*pt)); 1364104Swollman pt->part1.dev = dev1 = make_dev(&nmdm_cdevsw, n+n, 1374104Swollman 0, 0, 0666, "nmdm%dA", n); 1381541Srgrimes pt->part2.dev = dev2 = make_dev(&nmdm_cdevsw, n+n+1, 1391541Srgrimes 0, 0, 0666, "nmdm%dB", n); 1401541Srgrimes 1411541Srgrimes dev1->si_drv1 = dev2->si_drv1 = pt; 1421541Srgrimes dev1->si_tty = &pt->part1.nm_tty; 1431541Srgrimes dev2->si_tty = &pt->part2.nm_tty; 1441541Srgrimes ttyregister(&pt->part1.nm_tty); 14586764Sjlemon ttyregister(&pt->part2.nm_tty); 1461541Srgrimes pt->part1.nm_tty.t_oproc = nmdmstart; 1471541Srgrimes pt->part2.nm_tty.t_oproc = nmdmstart; 14817835Sjulian pt->part1.nm_tty.t_stop = nmdmstop; 1491541Srgrimes pt->part2.nm_tty.t_dev = dev1; 1501541Srgrimes pt->part1.nm_tty.t_dev = dev2; 1511541Srgrimes pt->part2.nm_tty.t_stop = nmdmstop; 1521541Srgrimes} 1531541Srgrimes 154122921Sandre/*ARGSUSED*/ 155122921Sandrestatic int 156122921Sandrenmdmopen(dev, flag, devtype, p) 157122921Sandre dev_t dev; 158122921Sandre int flag, devtype; 1595099Swollman struct proc *p; 1605099Swollman{ 16118839Swollman register struct tty *tp, *tp2; 1626245Swollman int error; 16315652Swollman int minr; 16415652Swollman dev_t nextdev; 16515652Swollman struct nm_softc *pti; 16615652Swollman int is_b; 1671541Srgrimes int pair; 1681541Srgrimes struct softpart *ourpart, *otherpart; 1691541Srgrimes 1701541Srgrimes /* 1711541Srgrimes * XXX: Gross hack for DEVFS: 1721541Srgrimes * If we openned this device, ensure we have the 1731541Srgrimes * next one too, so people can open it. 1741541Srgrimes */ 1751541Srgrimes minr = dev2unit(dev); 1761541Srgrimes pair = minr >> 1; 1771541Srgrimes is_b = minr & 1; 1781541Srgrimes 1791541Srgrimes if (pair < 127) { 1801541Srgrimes nextdev = makedev(major(dev), (pair+pair) + 1); 1811541Srgrimes if (!nextdev->si_drv1) { 1821541Srgrimes nmdminit(pair + 1); 1831541Srgrimes } 1841541Srgrimes } 1851541Srgrimes if (!dev->si_drv1) 1861541Srgrimes nmdminit(pair); 1871541Srgrimes 1881541Srgrimes if (!dev->si_drv1) 1891541Srgrimes return(ENXIO); 1901541Srgrimes 1911541Srgrimes pti = dev->si_drv1; 1921541Srgrimes if (is_b) 1931541Srgrimes tp = &pti->part2.nm_tty; 1941541Srgrimes else 1951541Srgrimes tp = &pti->part1.nm_tty; 1965791Swollman GETPARTS(tp, ourpart, otherpart); 1971541Srgrimes tp2 = &otherpart->nm_tty; 19851252Sru ourpart->modemsignals |= TIOCM_LE; 19951252Sru 20051252Sru if ((tp->t_state & TS_ISOPEN) == 0) { 2011541Srgrimes ttychars(tp); /* Set up default chars */ 2021541Srgrimes tp->t_iflag = TTYDEF_IFLAG; 2031541Srgrimes tp->t_oflag = TTYDEF_OFLAG; 2041541Srgrimes tp->t_lflag = TTYDEF_LFLAG; 2051541Srgrimes tp->t_cflag = TTYDEF_CFLAG; 2061541Srgrimes tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 2071541Srgrimes } else if (tp->t_state & TS_XCLUDE && suser(p)) { 2081541Srgrimes return (EBUSY); 2091541Srgrimes } else if (pti->pt_prison != p->p_ucred->cr_prison) { 2101541Srgrimes return (EBUSY); 2111541Srgrimes } 2121541Srgrimes 2131541Srgrimes /* 2141541Srgrimes * If the other side is open we have carrier 21521666Swollman */ 21621666Swollman if (tp2->t_state & TS_ISOPEN) { 21789498Sru (void)(*linesw[tp->t_line].l_modem)(tp, 1); 2181541Srgrimes } 21951252Sru 22051252Sru /* 22151252Sru * And the other side gets carrier as we are now open. 2221541Srgrimes */ 2231541Srgrimes (void)(*linesw[tp2->t_line].l_modem)(tp2, 1); 22451252Sru 2251541Srgrimes /* External processing makes no sense here */ 2261541Srgrimes tp->t_lflag &= ~EXTPROC; 2271541Srgrimes 2281541Srgrimes /* 2291541Srgrimes * Wait here if we don't have carrier. 2301541Srgrimes */ 2311541Srgrimes#if 0 23251252Sru while ((tp->t_state & TS_CARR_ON) == 0) { 2331541Srgrimes if (flag & FNONBLOCK) 2341541Srgrimes break; 2351541Srgrimes error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 2361541Srgrimes "nmdopn", 0); 2371541Srgrimes if (error) 2381541Srgrimes return (error); 2391541Srgrimes } 2401541Srgrimes#endif 2411541Srgrimes 2421541Srgrimes /* 2431541Srgrimes * Give the line disciplin a chance to set this end up. 2441541Srgrimes */ 2451541Srgrimes error = (*linesw[tp->t_line].l_open)(dev, tp); 2461541Srgrimes 2471541Srgrimes /* 2481541Srgrimes * Wake up the other side. 2491541Srgrimes * Theoretically not needed. 2501541Srgrimes */ 2511541Srgrimes ourpart->modemsignals |= TIOCM_DTR; 2521541Srgrimes nmdm_crossover(pti, ourpart, otherpart); 2531541Srgrimes if (error == 0) 2541541Srgrimes wakeup_other(tp, FREAD|FWRITE); /* XXX */ 2551541Srgrimes return (error); 2561541Srgrimes} 2571541Srgrimes 2581541Srgrimesstatic int 25985074Srunmdmclose(dev, flag, mode, p) 26085074Sru dev_t dev; 26185074Sru int flag, mode; 2621541Srgrimes struct proc *p; 2631541Srgrimes{ 26455205Speter register struct tty *tp, *tp2; 265117752Shsu int err; 266120727Ssam struct softpart *ourpart, *otherpart; 267120727Ssam 268120727Ssam /* 269120727Ssam * let the other end know that the game is up 270120727Ssam */ 271120727Ssam tp = dev->si_tty; 272117752Shsu GETPARTS(tp, ourpart, otherpart); 273122334Ssam tp2 = &otherpart->nm_tty; 274122334Ssam (void)(*linesw[tp2->t_line].l_modem)(tp2, 0); 275122334Ssam 276122334Ssam /* 277122334Ssam * XXX MDMBUF makes no sense for nmdms but would inhibit the above 278122334Ssam * l_modem(). CLOCAL makes sense but isn't supported. Special 279122334Ssam * l_modem()s that ignore carrier drop make no sense for nmdms but 280122334Ssam * may be in use because other parts of the line discipline make 281122334Ssam * sense for nmdms. Recover by doing everything that a normal 282122334Ssam * ttymodem() would have done except for sending a SIGHUP. 283122334Ssam */ 284122334Ssam if (tp2->t_state & TS_ISOPEN) { 285122334Ssam tp2->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 286122334Ssam tp2->t_state |= TS_ZOMBIE; 287122334Ssam ttyflush(tp2, FREAD | FWRITE); 288122334Ssam } 289122334Ssam 290122334Ssam err = (*linesw[tp->t_line].l_close)(tp, flag); 291122334Ssam ourpart->modemsignals &= ~TIOCM_DTR; 292122334Ssam nmdm_crossover(dev->si_drv1, ourpart, otherpart); 293122334Ssam nmdmstop(tp, FREAD|FWRITE); 294122334Ssam (void) ttyclose(tp); 29546568Speter return (err); 296122334Ssam} 297122334Ssam 298122334Ssamstatic int 299120727Ssamnmdmread(dev, uio, flag) 3001541Srgrimes dev_t dev; 3019759Sbde struct uio *uio; 3021541Srgrimes int flag; 30321666Swollman{ 30421666Swollman int error = 0; 30592725Salfred struct tty *tp, *tp2; 30692725Salfred struct softpart *ourpart, *otherpart; 30792725Salfred 30892725Salfred tp = dev->si_tty; 30992725Salfred GETPARTS(tp, ourpart, otherpart); 31092725Salfred tp2 = &otherpart->nm_tty; 31192725Salfred 312120727Ssam#if 0 31392725Salfred if (tp2->t_state & TS_ISOPEN) { 31492725Salfred error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 315120727Ssam wakeup_other(tp, FWRITE); 316120727Ssam } else { 317121770Ssam if (flag & IO_NDELAY) { 31892725Salfred return (EWOULDBLOCK); 31992725Salfred } 32092725Salfred error = tsleep(TSA_PTC_READ(tp), 32192725Salfred TTIPRI | PCATCH, "nmdout", 0); 322120727Ssam } 32392725Salfred } 32492725Salfred#else 32592725Salfred if ((error = (*linesw[tp->t_line].l_read)(tp, uio, flag)) == 0) 326111767Smdodd wakeup_other(tp, FWRITE); 3271541Srgrimes#endif 3282168Spaul return (error); 3292168Spaul} 330 331/* 332 * Write to pseudo-tty. 333 * Wakeups of controlling tty will happen 334 * indirectly, when tty driver calls nmdmstart. 335 */ 336static int 337nmdmwrite(dev, uio, flag) 338 dev_t dev; 339 struct uio *uio; 340 int flag; 341{ 342 register u_char *cp = 0; 343 register int cc = 0; 344 u_char locbuf[BUFSIZ]; 345 int cnt = 0; 346 int error = 0; 347 struct tty *tp1, *tp; 348 struct softpart *ourpart, *otherpart; 349 350 tp1 = dev->si_tty; 351 /* 352 * Get the other tty struct. 353 * basically we are writing into the INPUT side of the other device. 354 */ 355 GETPARTS(tp1, ourpart, otherpart); 356 tp = &otherpart->nm_tty; 357 358again: 359 if ((tp->t_state & TS_ISOPEN) == 0) 360 return (EIO); 361 while (uio->uio_resid > 0 || cc > 0) { 362 /* 363 * Fill up the buffer if it's empty 364 */ 365 if (cc == 0) { 366 cc = min(uio->uio_resid, BUFSIZ); 367 cp = locbuf; 368 error = uiomove((caddr_t)cp, cc, uio); 369 if (error) 370 return (error); 371 /* check again for safety */ 372 if ((tp->t_state & TS_ISOPEN) == 0) { 373 /* adjust for data copied in but not written */ 374 uio->uio_resid += cc; 375 return (EIO); 376 } 377 } 378 while (cc > 0) { 379 if (((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= (TTYHOG-2)) 380 && ((tp->t_canq.c_cc > 0) || !(tp->t_iflag&ICANON))) { 381 /* 382 * Come here to wait for space in outq, 383 * or space in rawq, or an empty canq. 384 */ 385 wakeup(TSA_HUP_OR_INPUT(tp)); 386 if ((tp->t_state & TS_CONNECTED) == 0) { 387 /* 388 * Data piled up because not connected. 389 * Adjust for data copied in but 390 * not written. 391 */ 392 uio->uio_resid += cc; 393 return (EIO); 394 } 395 if (flag & IO_NDELAY) { 396 /* 397 * Don't wait if asked not to. 398 * Adjust for data copied in but 399 * not written. 400 */ 401 uio->uio_resid += cc; 402 if (cnt == 0) 403 return (EWOULDBLOCK); 404 return (0); 405 } 406 error = tsleep(TSA_PTC_WRITE(tp), 407 TTOPRI | PCATCH, "nmdout", 0); 408 if (error) { 409 /* 410 * Tsleep returned (signal?). 411 * Go find out what the user wants. 412 * adjust for data copied in but 413 * not written 414 */ 415 uio->uio_resid += cc; 416 return (error); 417 } 418 goto again; 419 } 420 (*linesw[tp->t_line].l_rint)(*cp++, tp); 421 cnt++; 422 cc--; 423 } 424 cc = 0; 425 } 426 return (0); 427} 428 429/* 430 * Start output on pseudo-tty. 431 * Wake up process selecting or sleeping for input from controlling tty. 432 */ 433static void 434nmdmstart(tp) 435 struct tty *tp; 436{ 437 register struct nm_softc *pti = tp->t_dev->si_drv1; 438 439 if (tp->t_state & TS_TTSTOP) 440 return; 441 pti->pt_flags &= ~PF_STOPPED; 442 wakeup_other(tp, FREAD); 443} 444 445/* Wakes up the OTHER tty;*/ 446static void 447wakeup_other(tp, flag) 448 struct tty *tp; 449 int flag; 450{ 451 struct softpart *ourpart, *otherpart; 452 453 GETPARTS(tp, ourpart, otherpart); 454 if (flag & FREAD) { 455 selwakeup(&otherpart->nm_tty.t_rsel); 456 wakeup(TSA_PTC_READ((&otherpart->nm_tty))); 457 } 458 if (flag & FWRITE) { 459 selwakeup(&otherpart->nm_tty.t_wsel); 460 wakeup(TSA_PTC_WRITE((&otherpart->nm_tty))); 461 } 462} 463 464static void 465nmdmstop(tp, flush) 466 register struct tty *tp; 467 int flush; 468{ 469 struct nm_softc *pti = tp->t_dev->si_drv1; 470 int flag; 471 472 /* note: FLUSHREAD and FLUSHWRITE already ok */ 473 if (flush == 0) { 474 flush = TIOCPKT_STOP; 475 pti->pt_flags |= PF_STOPPED; 476 } else 477 pti->pt_flags &= ~PF_STOPPED; 478 /* change of perspective */ 479 flag = 0; 480 if (flush & FREAD) 481 flag |= FWRITE; 482 if (flush & FWRITE) 483 flag |= FREAD; 484 wakeup_other(tp, flag); 485} 486 487#if 0 488static int 489nmdmpoll(dev_t dev, int events, struct proc *p) 490{ 491 register struct tty *tp = dev->si_tty; 492 register struct tty *tp2; 493 int revents = 0; 494 int s; 495 struct softpart *ourpart, *otherpart; 496 497 GETPARTS(tp, ourpart, otherpart); 498 tp2 = &otherpart->nm_tty; 499 500 if ((tp->t_state & TS_CONNECTED) == 0) 501 return (seltrue(dev, events, p) | POLLHUP); 502 503 /* 504 * Need to block timeouts (ttrstart). 505 */ 506 s = spltty(); 507 508 /* 509 * First check if there is something to report immediatly. 510 */ 511 if ((events & (POLLIN | POLLRDNORM))) { 512 if (tp->t_iflag & ICANON) { 513 if (tp->t_canq.c_cc) 514 revents |= events & (POLLIN | POLLRDNORM); 515 } else { 516 if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 517 revents |= events & (POLLIN | POLLRDNORM); 518 } 519 } 520 521 /* 522 * check if there is room in the other tty's input buffers. 523 */ 524 if ((events & (POLLOUT | POLLWRNORM)) 525 && ((tp2->t_rawq.c_cc + tp2->t_canq.c_cc < TTYHOG - 2) 526 || (tp2->t_canq.c_cc == 0 && (tp2->t_iflag & ICANON)))) { 527 revents |= events & (POLLOUT | POLLWRNORM); 528 } 529 530 if (events & POLLHUP) 531 if ((tp->t_state & TS_CARR_ON) == 0) 532 revents |= POLLHUP; 533 534 /* 535 * If nothing immediate, set us to return when something IS found. 536 */ 537 if (revents == 0) { 538 if (events & (POLLIN | POLLRDNORM)) 539 selrecord(p, &tp->t_rsel); 540 541 if (events & (POLLOUT | POLLWRNORM)) 542 selrecord(p, &tp->t_wsel); 543 } 544 splx(s); 545 546 return (revents); 547} 548#endif /* 0 */ 549 550/*ARGSUSED*/ 551static int 552nmdmioctl(dev, cmd, data, flag, p) 553 dev_t dev; 554 u_long cmd; 555 caddr_t data; 556 int flag; 557 struct proc *p; 558{ 559 register struct tty *tp = dev->si_tty; 560 struct nm_softc *pti = dev->si_drv1; 561 int error, s; 562 register struct tty *tp2; 563 struct softpart *ourpart, *otherpart; 564 565 s = spltty(); 566 GETPARTS(tp, ourpart, otherpart); 567 tp2 = &otherpart->nm_tty; 568 569 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 570 if (error == ENOIOCTL) 571 error = ttioctl(tp, cmd, data, flag); 572 if (error == ENOIOCTL) { 573 switch (cmd) { 574 case TIOCSBRK: 575 otherpart->gotbreak = 1; 576 break; 577 case TIOCCBRK: 578 break; 579 case TIOCSDTR: 580 ourpart->modemsignals |= TIOCM_DTR; 581 break; 582 case TIOCCDTR: 583 ourpart->modemsignals &= TIOCM_DTR; 584 break; 585 case TIOCMSET: 586 ourpart->modemsignals = *(int *)data; 587 otherpart->modemsignals = *(int *)data; 588 break; 589 case TIOCMBIS: 590 ourpart->modemsignals |= *(int *)data; 591 break; 592 case TIOCMBIC: 593 ourpart->modemsignals &= ~(*(int *)data); 594 otherpart->modemsignals &= ~(*(int *)data); 595 break; 596 case TIOCMGET: 597 *(int *)data = ourpart->modemsignals; 598 break; 599 case TIOCMSDTRWAIT: 600 break; 601 case TIOCMGDTRWAIT: 602 *(int *)data = 0; 603 break; 604 case TIOCTIMESTAMP: 605 case TIOCDCDTIMESTAMP: 606 default: 607 splx(s); 608 error = ENOTTY; 609 return (error); 610 } 611 error = 0; 612 nmdm_crossover(pti, ourpart, otherpart); 613 } 614 splx(s); 615 return (error); 616} 617 618static void 619nmdm_crossover(struct nm_softc *pti, 620 struct softpart *ourpart, 621 struct softpart *otherpart) 622{ 623 otherpart->modemsignals &= ~(TIOCM_CTS|TIOCM_CAR); 624 if (ourpart->modemsignals & TIOCM_RTS) 625 otherpart->modemsignals |= TIOCM_CTS; 626 if (ourpart->modemsignals & TIOCM_DTR) 627 otherpart->modemsignals |= TIOCM_CAR; 628} 629 630 631 632static void nmdm_drvinit __P((void *unused)); 633 634static void 635nmdm_drvinit(unused) 636 void *unused; 637{ 638 cdevsw_add(&nmdm_cdevsw); 639 /* XXX: Gross hack for DEVFS */ 640 nmdminit(0); 641} 642 643SYSINIT(nmdmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,nmdm_drvinit,NULL) 644