1737a1286SJulian Elischer /* 2737a1286SJulian Elischer * Copyright (c) 1982, 1986, 1989, 1993 3737a1286SJulian Elischer * The Regents of the University of California. All rights reserved. 4737a1286SJulian Elischer * 5737a1286SJulian Elischer * Redistribution and use in source and binary forms, with or without 6737a1286SJulian Elischer * modification, are permitted provided that the following conditions 7737a1286SJulian Elischer * are met: 8737a1286SJulian Elischer * 1. Redistributions of source code must retain the above copyright 9737a1286SJulian Elischer * notice, this list of conditions and the following disclaimer. 10737a1286SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 11737a1286SJulian Elischer * notice, this list of conditions and the following disclaimer in the 12737a1286SJulian Elischer * documentation and/or other materials provided with the distribution. 13737a1286SJulian Elischer * 3. All advertising materials mentioning features or use of this software 14737a1286SJulian Elischer * must display the following acknowledgement: 15737a1286SJulian Elischer * This product includes software developed by the University of 16737a1286SJulian Elischer * California, Berkeley and its contributors. 17737a1286SJulian Elischer * 4. Neither the name of the University nor the names of its contributors 18737a1286SJulian Elischer * may be used to endorse or promote products derived from this software 19737a1286SJulian Elischer * without specific prior written permission. 20737a1286SJulian Elischer * 21737a1286SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22737a1286SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23737a1286SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24737a1286SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25737a1286SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26737a1286SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27737a1286SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28737a1286SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29737a1286SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30737a1286SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31737a1286SJulian Elischer * SUCH DAMAGE. 32737a1286SJulian Elischer * 33737a1286SJulian Elischer * $FreeBSD$ 34737a1286SJulian Elischer */ 35737a1286SJulian Elischer 36737a1286SJulian Elischer /* 37737a1286SJulian Elischer * Pseudo-nulmodem Driver 38737a1286SJulian Elischer */ 39737a1286SJulian Elischer #include "opt_compat.h" 40737a1286SJulian Elischer #include <sys/param.h> 41737a1286SJulian Elischer #include <sys/systm.h> 42737a1286SJulian Elischer #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 43737a1286SJulian Elischer #include <sys/ioctl_compat.h> 44737a1286SJulian Elischer #endif 45737a1286SJulian Elischer #include <sys/proc.h> 46737a1286SJulian Elischer #include <sys/tty.h> 47737a1286SJulian Elischer #include <sys/conf.h> 48737a1286SJulian Elischer #include <sys/fcntl.h> 49737a1286SJulian Elischer #include <sys/poll.h> 50737a1286SJulian Elischer #include <sys/kernel.h> 51737a1286SJulian Elischer #include <sys/vnode.h> 52737a1286SJulian Elischer #include <sys/signalvar.h> 53737a1286SJulian Elischer #include <sys/malloc.h> 54737a1286SJulian Elischer 55737a1286SJulian Elischer MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures"); 56737a1286SJulian Elischer 57737a1286SJulian Elischer static void nmdmstart __P((struct tty *tp)); 58737a1286SJulian Elischer static void nmdmstop __P((struct tty *tp, int rw)); 59737a1286SJulian Elischer static void wakeup_other __P((struct tty *tp, int flag)); 60737a1286SJulian Elischer static void nmdminit __P((int n)); 61737a1286SJulian Elischer 62737a1286SJulian Elischer static d_open_t nmdmopen; 63737a1286SJulian Elischer static d_close_t nmdmclose; 64737a1286SJulian Elischer static d_read_t nmdmread; 65737a1286SJulian Elischer static d_write_t nmdmwrite; 66737a1286SJulian Elischer static d_ioctl_t nmdmioctl; 67737a1286SJulian Elischer 68737a1286SJulian Elischer #define CDEV_MAJOR 18 69737a1286SJulian Elischer static struct cdevsw nmdm_cdevsw = { 70737a1286SJulian Elischer /* open */ nmdmopen, 71737a1286SJulian Elischer /* close */ nmdmclose, 72737a1286SJulian Elischer /* read */ nmdmread, 73737a1286SJulian Elischer /* write */ nmdmwrite, 74737a1286SJulian Elischer /* ioctl */ nmdmioctl, 75737a1286SJulian Elischer /* poll */ ttypoll, 76737a1286SJulian Elischer /* mmap */ nommap, 77737a1286SJulian Elischer /* strategy */ nostrategy, 78737a1286SJulian Elischer /* name */ "pts", 79737a1286SJulian Elischer /* maj */ CDEV_MAJOR, 80737a1286SJulian Elischer /* dump */ nodump, 81737a1286SJulian Elischer /* psize */ nopsize, 82737a1286SJulian Elischer /* flags */ D_TTY, 83737a1286SJulian Elischer /* bmaj */ -1 84737a1286SJulian Elischer }; 85737a1286SJulian Elischer 86737a1286SJulian Elischer #define BUFSIZ 100 /* Chunk size iomoved to/from user */ 87737a1286SJulian Elischer 88737a1286SJulian Elischer struct softpart { 89737a1286SJulian Elischer struct tty nm_tty; 90737a1286SJulian Elischer dev_t dev; 91737a1286SJulian Elischer int modemsignals; /* bits defined in sys/ttycom.h */ 92737a1286SJulian Elischer int gotbreak; 93737a1286SJulian Elischer }; 94737a1286SJulian Elischer 95737a1286SJulian Elischer struct nm_softc { 96737a1286SJulian Elischer int pt_flags; 97737a1286SJulian Elischer struct softpart part1, part2; 98737a1286SJulian Elischer struct prison *pt_prison; 99737a1286SJulian Elischer }; 100737a1286SJulian Elischer 101737a1286SJulian Elischer #define PF_STOPPED 0x10 /* user told stopped */ 102737a1286SJulian Elischer 103737a1286SJulian Elischer static void 104737a1286SJulian Elischer nmdm_crossover(struct nm_softc *pti, 105737a1286SJulian Elischer struct softpart *ourpart, 106737a1286SJulian Elischer struct softpart *otherpart); 107737a1286SJulian Elischer 108737a1286SJulian Elischer #define GETPARTS(tp, ourpart, otherpart) \ 109737a1286SJulian Elischer do { \ 110737a1286SJulian Elischer struct nm_softc *pti = tp->t_dev->si_drv1; \ 111737a1286SJulian Elischer if (tp == &pti->part1.nm_tty) { \ 112737a1286SJulian Elischer ourpart = &pti->part1; \ 113737a1286SJulian Elischer otherpart = &pti->part2; \ 114737a1286SJulian Elischer } else { \ 115737a1286SJulian Elischer ourpart = &pti->part2; \ 116737a1286SJulian Elischer otherpart = &pti->part1; \ 117737a1286SJulian Elischer } \ 118737a1286SJulian Elischer } while (0) 119737a1286SJulian Elischer 120737a1286SJulian Elischer /* 121737a1286SJulian Elischer * This function creates and initializes a pair of ttys. 122737a1286SJulian Elischer */ 123737a1286SJulian Elischer static void 124737a1286SJulian Elischer nmdminit(n) 125737a1286SJulian Elischer int n; 126737a1286SJulian Elischer { 127737a1286SJulian Elischer dev_t dev1, dev2; 128737a1286SJulian Elischer struct nm_softc *pt; 129737a1286SJulian Elischer 130737a1286SJulian Elischer /* For now we only map the lower 8 bits of the minor */ 131737a1286SJulian Elischer if (n & ~0xff) 132737a1286SJulian Elischer return; 133737a1286SJulian Elischer 134737a1286SJulian Elischer pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK); 135737a1286SJulian Elischer bzero(pt, sizeof(*pt)); 136737a1286SJulian Elischer pt->part1.dev = dev1 = make_dev(&nmdm_cdevsw, n+n, 137737a1286SJulian Elischer 0, 0, 0666, "nmdm%dA", n); 138737a1286SJulian Elischer pt->part2.dev = dev2 = make_dev(&nmdm_cdevsw, n+n+1, 139737a1286SJulian Elischer 0, 0, 0666, "nmdm%dB", n); 140737a1286SJulian Elischer 141737a1286SJulian Elischer dev1->si_drv1 = dev2->si_drv1 = pt; 142737a1286SJulian Elischer dev1->si_tty = &pt->part1.nm_tty; 143737a1286SJulian Elischer dev2->si_tty = &pt->part2.nm_tty; 144737a1286SJulian Elischer ttyregister(&pt->part1.nm_tty); 145737a1286SJulian Elischer ttyregister(&pt->part2.nm_tty); 146737a1286SJulian Elischer pt->part1.nm_tty.t_oproc = nmdmstart; 147737a1286SJulian Elischer pt->part2.nm_tty.t_oproc = nmdmstart; 148737a1286SJulian Elischer pt->part1.nm_tty.t_stop = nmdmstop; 149737a1286SJulian Elischer pt->part2.nm_tty.t_dev = dev1; 150737a1286SJulian Elischer pt->part1.nm_tty.t_dev = dev2; 151737a1286SJulian Elischer pt->part2.nm_tty.t_stop = nmdmstop; 152737a1286SJulian Elischer } 153737a1286SJulian Elischer 154737a1286SJulian Elischer /*ARGSUSED*/ 155737a1286SJulian Elischer static int 156737a1286SJulian Elischer nmdmopen(dev, flag, devtype, p) 157737a1286SJulian Elischer dev_t dev; 158737a1286SJulian Elischer int flag, devtype; 159737a1286SJulian Elischer struct proc *p; 160737a1286SJulian Elischer { 161737a1286SJulian Elischer register struct tty *tp, *tp2; 162737a1286SJulian Elischer int error; 163737a1286SJulian Elischer int minr; 164737a1286SJulian Elischer dev_t nextdev; 165737a1286SJulian Elischer struct nm_softc *pti; 166737a1286SJulian Elischer int is_b; 167737a1286SJulian Elischer int pair; 168737a1286SJulian Elischer struct softpart *ourpart, *otherpart; 169737a1286SJulian Elischer 170737a1286SJulian Elischer /* 171737a1286SJulian Elischer * XXX: Gross hack for DEVFS: 172737a1286SJulian Elischer * If we openned this device, ensure we have the 173737a1286SJulian Elischer * next one too, so people can open it. 174737a1286SJulian Elischer */ 175737a1286SJulian Elischer minr = dev2unit(dev); 176737a1286SJulian Elischer pair = minr >> 1; 177737a1286SJulian Elischer is_b = minr & 1; 178737a1286SJulian Elischer 179737a1286SJulian Elischer if (pair < 127) { 180737a1286SJulian Elischer nextdev = makedev(major(dev), (pair+pair) + 1); 181737a1286SJulian Elischer if (!nextdev->si_drv1) { 182737a1286SJulian Elischer nmdminit(pair + 1); 183737a1286SJulian Elischer } 184737a1286SJulian Elischer } 185737a1286SJulian Elischer if (!dev->si_drv1) 186737a1286SJulian Elischer nmdminit(pair); 187737a1286SJulian Elischer 188737a1286SJulian Elischer if (!dev->si_drv1) 189737a1286SJulian Elischer return(ENXIO); 190737a1286SJulian Elischer 191737a1286SJulian Elischer pti = dev->si_drv1; 192737a1286SJulian Elischer if (is_b) 193737a1286SJulian Elischer tp = &pti->part2.nm_tty; 194737a1286SJulian Elischer else 195737a1286SJulian Elischer tp = &pti->part1.nm_tty; 196737a1286SJulian Elischer GETPARTS(tp, ourpart, otherpart); 197737a1286SJulian Elischer tp2 = &otherpart->nm_tty; 198737a1286SJulian Elischer ourpart->modemsignals |= TIOCM_LE; 199737a1286SJulian Elischer 200737a1286SJulian Elischer if ((tp->t_state & TS_ISOPEN) == 0) { 201737a1286SJulian Elischer ttychars(tp); /* Set up default chars */ 202737a1286SJulian Elischer tp->t_iflag = TTYDEF_IFLAG; 203737a1286SJulian Elischer tp->t_oflag = TTYDEF_OFLAG; 204737a1286SJulian Elischer tp->t_lflag = TTYDEF_LFLAG; 205737a1286SJulian Elischer tp->t_cflag = TTYDEF_CFLAG; 206737a1286SJulian Elischer tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 207737a1286SJulian Elischer } else if (tp->t_state & TS_XCLUDE && suser(p)) { 208737a1286SJulian Elischer return (EBUSY); 209737a1286SJulian Elischer } else if (pti->pt_prison != p->p_prison) { 210737a1286SJulian Elischer return (EBUSY); 211737a1286SJulian Elischer } 212737a1286SJulian Elischer 213737a1286SJulian Elischer /* 214737a1286SJulian Elischer * If the other side is open we have carrier 215737a1286SJulian Elischer */ 216737a1286SJulian Elischer if (tp2->t_state & TS_ISOPEN) { 217737a1286SJulian Elischer (void)(*linesw[tp->t_line].l_modem)(tp, 1); 218737a1286SJulian Elischer } 219737a1286SJulian Elischer 220737a1286SJulian Elischer /* 221737a1286SJulian Elischer * And the other side gets carrier as we are now open. 222737a1286SJulian Elischer */ 223737a1286SJulian Elischer (void)(*linesw[tp2->t_line].l_modem)(tp2, 1); 224737a1286SJulian Elischer 225737a1286SJulian Elischer /* External processing makes no sense here */ 226737a1286SJulian Elischer tp->t_lflag &= ~EXTPROC; 227737a1286SJulian Elischer 228737a1286SJulian Elischer /* 229737a1286SJulian Elischer * Wait here if we don't have carrier. 230737a1286SJulian Elischer */ 231737a1286SJulian Elischer #if 0 232737a1286SJulian Elischer while ((tp->t_state & TS_CARR_ON) == 0) { 233737a1286SJulian Elischer if (flag & FNONBLOCK) 234737a1286SJulian Elischer break; 235737a1286SJulian Elischer error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 236737a1286SJulian Elischer "nmdopn", 0); 237737a1286SJulian Elischer if (error) 238737a1286SJulian Elischer return (error); 239737a1286SJulian Elischer } 240737a1286SJulian Elischer #endif 241737a1286SJulian Elischer 242737a1286SJulian Elischer /* 243737a1286SJulian Elischer * Give the line disciplin a chance to set this end up. 244737a1286SJulian Elischer */ 245737a1286SJulian Elischer error = (*linesw[tp->t_line].l_open)(dev, tp); 246737a1286SJulian Elischer 247737a1286SJulian Elischer /* 248737a1286SJulian Elischer * Wake up the other side. 249737a1286SJulian Elischer * Theoretically not needed. 250737a1286SJulian Elischer */ 251737a1286SJulian Elischer ourpart->modemsignals |= TIOCM_DTR; 252737a1286SJulian Elischer nmdm_crossover(pti, ourpart, otherpart); 253737a1286SJulian Elischer if (error == 0) 254737a1286SJulian Elischer wakeup_other(tp, FREAD|FWRITE); /* XXX */ 255737a1286SJulian Elischer return (error); 256737a1286SJulian Elischer } 257737a1286SJulian Elischer 258737a1286SJulian Elischer static int 259737a1286SJulian Elischer nmdmclose(dev, flag, mode, p) 260737a1286SJulian Elischer dev_t dev; 261737a1286SJulian Elischer int flag, mode; 262737a1286SJulian Elischer struct proc *p; 263737a1286SJulian Elischer { 264737a1286SJulian Elischer register struct tty *tp, *tp2; 265737a1286SJulian Elischer int err; 266737a1286SJulian Elischer struct softpart *ourpart, *otherpart; 267737a1286SJulian Elischer 268737a1286SJulian Elischer /* 269737a1286SJulian Elischer * let the other end know that the game is up 270737a1286SJulian Elischer */ 271737a1286SJulian Elischer tp = dev->si_tty; 272737a1286SJulian Elischer GETPARTS(tp, ourpart, otherpart); 273737a1286SJulian Elischer tp2 = &otherpart->nm_tty; 274737a1286SJulian Elischer (void)(*linesw[tp2->t_line].l_modem)(tp2, 0); 275737a1286SJulian Elischer 276737a1286SJulian Elischer /* 277737a1286SJulian Elischer * XXX MDMBUF makes no sense for nmdms but would inhibit the above 278737a1286SJulian Elischer * l_modem(). CLOCAL makes sense but isn't supported. Special 279737a1286SJulian Elischer * l_modem()s that ignore carrier drop make no sense for nmdms but 280737a1286SJulian Elischer * may be in use because other parts of the line discipline make 281737a1286SJulian Elischer * sense for nmdms. Recover by doing everything that a normal 282737a1286SJulian Elischer * ttymodem() would have done except for sending a SIGHUP. 283737a1286SJulian Elischer */ 284737a1286SJulian Elischer if (tp2->t_state & TS_ISOPEN) { 285737a1286SJulian Elischer tp2->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 286737a1286SJulian Elischer tp2->t_state |= TS_ZOMBIE; 287737a1286SJulian Elischer ttyflush(tp2, FREAD | FWRITE); 288737a1286SJulian Elischer } 289737a1286SJulian Elischer 290737a1286SJulian Elischer err = (*linesw[tp->t_line].l_close)(tp, flag); 291737a1286SJulian Elischer ourpart->modemsignals &= ~TIOCM_DTR; 292737a1286SJulian Elischer nmdm_crossover(dev->si_drv1, ourpart, otherpart); 293737a1286SJulian Elischer nmdmstop(tp, FREAD|FWRITE); 294737a1286SJulian Elischer (void) ttyclose(tp); 295737a1286SJulian Elischer return (err); 296737a1286SJulian Elischer } 297737a1286SJulian Elischer 298737a1286SJulian Elischer static int 299737a1286SJulian Elischer nmdmread(dev, uio, flag) 300737a1286SJulian Elischer dev_t dev; 301737a1286SJulian Elischer struct uio *uio; 302737a1286SJulian Elischer int flag; 303737a1286SJulian Elischer { 304737a1286SJulian Elischer int error = 0; 305737a1286SJulian Elischer struct tty *tp, *tp2; 306737a1286SJulian Elischer struct softpart *ourpart, *otherpart; 307737a1286SJulian Elischer 308737a1286SJulian Elischer tp = dev->si_tty; 309737a1286SJulian Elischer GETPARTS(tp, ourpart, otherpart); 310737a1286SJulian Elischer tp2 = &otherpart->nm_tty; 311737a1286SJulian Elischer 312737a1286SJulian Elischer #if 0 313737a1286SJulian Elischer if (tp2->t_state & TS_ISOPEN) { 314737a1286SJulian Elischer error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 315737a1286SJulian Elischer wakeup_other(tp, FWRITE); 316737a1286SJulian Elischer } else { 317737a1286SJulian Elischer if (flag & IO_NDELAY) { 318737a1286SJulian Elischer return (EWOULDBLOCK); 319737a1286SJulian Elischer } 320737a1286SJulian Elischer error = tsleep(TSA_PTC_READ(tp), 321737a1286SJulian Elischer TTIPRI | PCATCH, "nmdout", 0); 322737a1286SJulian Elischer } 323737a1286SJulian Elischer } 324737a1286SJulian Elischer #else 325737a1286SJulian Elischer if ((error = (*linesw[tp->t_line].l_read)(tp, uio, flag)) == 0) 326737a1286SJulian Elischer wakeup_other(tp, FWRITE); 327737a1286SJulian Elischer #endif 328737a1286SJulian Elischer return (error); 329737a1286SJulian Elischer } 330737a1286SJulian Elischer 331737a1286SJulian Elischer /* 332737a1286SJulian Elischer * Write to pseudo-tty. 333737a1286SJulian Elischer * Wakeups of controlling tty will happen 334737a1286SJulian Elischer * indirectly, when tty driver calls nmdmstart. 335737a1286SJulian Elischer */ 336737a1286SJulian Elischer static int 337737a1286SJulian Elischer nmdmwrite(dev, uio, flag) 338737a1286SJulian Elischer dev_t dev; 339737a1286SJulian Elischer struct uio *uio; 340737a1286SJulian Elischer int flag; 341737a1286SJulian Elischer { 342737a1286SJulian Elischer register u_char *cp = 0; 343737a1286SJulian Elischer register int cc = 0; 344737a1286SJulian Elischer u_char locbuf[BUFSIZ]; 345737a1286SJulian Elischer int cnt = 0; 346737a1286SJulian Elischer int error = 0; 347737a1286SJulian Elischer struct tty *tp1, *tp; 348737a1286SJulian Elischer struct softpart *ourpart, *otherpart; 349737a1286SJulian Elischer 350737a1286SJulian Elischer tp1 = dev->si_tty; 351737a1286SJulian Elischer /* 352737a1286SJulian Elischer * Get the other tty struct. 353737a1286SJulian Elischer * basically we are writing into the INPUT side of the other device. 354737a1286SJulian Elischer */ 355737a1286SJulian Elischer GETPARTS(tp1, ourpart, otherpart); 356737a1286SJulian Elischer tp = &otherpart->nm_tty; 357737a1286SJulian Elischer 358737a1286SJulian Elischer again: 359737a1286SJulian Elischer if ((tp->t_state & TS_ISOPEN) == 0) 360737a1286SJulian Elischer return (EIO); 361737a1286SJulian Elischer while (uio->uio_resid > 0 || cc > 0) { 362737a1286SJulian Elischer /* 363737a1286SJulian Elischer * Fill up the buffer if it's empty 364737a1286SJulian Elischer */ 365737a1286SJulian Elischer if (cc == 0) { 366737a1286SJulian Elischer cc = min(uio->uio_resid, BUFSIZ); 367737a1286SJulian Elischer cp = locbuf; 368737a1286SJulian Elischer error = uiomove((caddr_t)cp, cc, uio); 369737a1286SJulian Elischer if (error) 370737a1286SJulian Elischer return (error); 371737a1286SJulian Elischer /* check again for safety */ 372737a1286SJulian Elischer if ((tp->t_state & TS_ISOPEN) == 0) { 373737a1286SJulian Elischer /* adjust for data copied in but not written */ 374737a1286SJulian Elischer uio->uio_resid += cc; 375737a1286SJulian Elischer return (EIO); 376737a1286SJulian Elischer } 377737a1286SJulian Elischer } 378737a1286SJulian Elischer while (cc > 0) { 379737a1286SJulian Elischer if (((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= (TTYHOG-2)) 380737a1286SJulian Elischer && ((tp->t_canq.c_cc > 0) || !(tp->t_iflag&ICANON))) { 381737a1286SJulian Elischer /* 382737a1286SJulian Elischer * Come here to wait for space in outq, 383737a1286SJulian Elischer * or space in rawq, or an empty canq. 384737a1286SJulian Elischer */ 385737a1286SJulian Elischer wakeup(TSA_HUP_OR_INPUT(tp)); 386737a1286SJulian Elischer if ((tp->t_state & TS_CONNECTED) == 0) { 387737a1286SJulian Elischer /* 388737a1286SJulian Elischer * Data piled up because not connected. 389737a1286SJulian Elischer * Adjust for data copied in but 390737a1286SJulian Elischer * not written. 391737a1286SJulian Elischer */ 392737a1286SJulian Elischer uio->uio_resid += cc; 393737a1286SJulian Elischer return (EIO); 394737a1286SJulian Elischer } 395737a1286SJulian Elischer if (flag & IO_NDELAY) { 396737a1286SJulian Elischer /* 397737a1286SJulian Elischer * Don't wait if asked not to. 398737a1286SJulian Elischer * Adjust for data copied in but 399737a1286SJulian Elischer * not written. 400737a1286SJulian Elischer */ 401737a1286SJulian Elischer uio->uio_resid += cc; 402737a1286SJulian Elischer if (cnt == 0) 403737a1286SJulian Elischer return (EWOULDBLOCK); 404737a1286SJulian Elischer return (0); 405737a1286SJulian Elischer } 406737a1286SJulian Elischer error = tsleep(TSA_PTC_WRITE(tp), 407737a1286SJulian Elischer TTOPRI | PCATCH, "nmdout", 0); 408737a1286SJulian Elischer if (error) { 409737a1286SJulian Elischer /* 410737a1286SJulian Elischer * Tsleep returned (signal?). 411737a1286SJulian Elischer * Go find out what the user wants. 412737a1286SJulian Elischer * adjust for data copied in but 413737a1286SJulian Elischer * not written 414737a1286SJulian Elischer */ 415737a1286SJulian Elischer uio->uio_resid += cc; 416737a1286SJulian Elischer return (error); 417737a1286SJulian Elischer } 418737a1286SJulian Elischer goto again; 419737a1286SJulian Elischer } 420737a1286SJulian Elischer (*linesw[tp->t_line].l_rint)(*cp++, tp); 421737a1286SJulian Elischer cnt++; 422737a1286SJulian Elischer cc--; 423737a1286SJulian Elischer } 424737a1286SJulian Elischer cc = 0; 425737a1286SJulian Elischer } 426737a1286SJulian Elischer return (0); 427737a1286SJulian Elischer } 428737a1286SJulian Elischer 429737a1286SJulian Elischer /* 430737a1286SJulian Elischer * Start output on pseudo-tty. 431737a1286SJulian Elischer * Wake up process selecting or sleeping for input from controlling tty. 432737a1286SJulian Elischer */ 433737a1286SJulian Elischer static void 434737a1286SJulian Elischer nmdmstart(tp) 435737a1286SJulian Elischer struct tty *tp; 436737a1286SJulian Elischer { 437737a1286SJulian Elischer register struct nm_softc *pti = tp->t_dev->si_drv1; 438737a1286SJulian Elischer 439737a1286SJulian Elischer if (tp->t_state & TS_TTSTOP) 440737a1286SJulian Elischer return; 441737a1286SJulian Elischer pti->pt_flags &= ~PF_STOPPED; 442737a1286SJulian Elischer wakeup_other(tp, FREAD); 443737a1286SJulian Elischer } 444737a1286SJulian Elischer 445737a1286SJulian Elischer /* Wakes up the OTHER tty;*/ 446737a1286SJulian Elischer static void 447737a1286SJulian Elischer wakeup_other(tp, flag) 448737a1286SJulian Elischer struct tty *tp; 449737a1286SJulian Elischer int flag; 450737a1286SJulian Elischer { 451737a1286SJulian Elischer struct softpart *ourpart, *otherpart; 452737a1286SJulian Elischer 453737a1286SJulian Elischer GETPARTS(tp, ourpart, otherpart); 454737a1286SJulian Elischer if (flag & FREAD) { 455737a1286SJulian Elischer selwakeup(&otherpart->nm_tty.t_rsel); 456737a1286SJulian Elischer wakeup(TSA_PTC_READ((&otherpart->nm_tty))); 457737a1286SJulian Elischer } 458737a1286SJulian Elischer if (flag & FWRITE) { 459737a1286SJulian Elischer selwakeup(&otherpart->nm_tty.t_wsel); 460737a1286SJulian Elischer wakeup(TSA_PTC_WRITE((&otherpart->nm_tty))); 461737a1286SJulian Elischer } 462737a1286SJulian Elischer } 463737a1286SJulian Elischer 464737a1286SJulian Elischer static void 465737a1286SJulian Elischer nmdmstop(tp, flush) 466737a1286SJulian Elischer register struct tty *tp; 467737a1286SJulian Elischer int flush; 468737a1286SJulian Elischer { 469737a1286SJulian Elischer struct nm_softc *pti = tp->t_dev->si_drv1; 470737a1286SJulian Elischer int flag; 471737a1286SJulian Elischer 472737a1286SJulian Elischer /* note: FLUSHREAD and FLUSHWRITE already ok */ 473737a1286SJulian Elischer if (flush == 0) { 474737a1286SJulian Elischer flush = TIOCPKT_STOP; 475737a1286SJulian Elischer pti->pt_flags |= PF_STOPPED; 476737a1286SJulian Elischer } else 477737a1286SJulian Elischer pti->pt_flags &= ~PF_STOPPED; 478737a1286SJulian Elischer /* change of perspective */ 479737a1286SJulian Elischer flag = 0; 480737a1286SJulian Elischer if (flush & FREAD) 481737a1286SJulian Elischer flag |= FWRITE; 482737a1286SJulian Elischer if (flush & FWRITE) 483737a1286SJulian Elischer flag |= FREAD; 484737a1286SJulian Elischer wakeup_other(tp, flag); 485737a1286SJulian Elischer } 486737a1286SJulian Elischer 487737a1286SJulian Elischer static int 488737a1286SJulian Elischer nmdmpoll(dev, events, p) 489737a1286SJulian Elischer dev_t dev; 490737a1286SJulian Elischer int events; 491737a1286SJulian Elischer struct proc *p; 492737a1286SJulian Elischer { 493737a1286SJulian Elischer register struct tty *tp = dev->si_tty; 494737a1286SJulian Elischer register struct tty *tp2; 495737a1286SJulian Elischer int revents = 0; 496737a1286SJulian Elischer int s; 497737a1286SJulian Elischer struct softpart *ourpart, *otherpart; 498737a1286SJulian Elischer 499737a1286SJulian Elischer GETPARTS(tp, ourpart, otherpart); 500737a1286SJulian Elischer tp2 = &otherpart->nm_tty; 501737a1286SJulian Elischer 502737a1286SJulian Elischer if ((tp->t_state & TS_CONNECTED) == 0) 503737a1286SJulian Elischer return (seltrue(dev, events, p) | POLLHUP); 504737a1286SJulian Elischer 505737a1286SJulian Elischer /* 506737a1286SJulian Elischer * Need to block timeouts (ttrstart). 507737a1286SJulian Elischer */ 508737a1286SJulian Elischer s = spltty(); 509737a1286SJulian Elischer 510737a1286SJulian Elischer /* 511737a1286SJulian Elischer * First check if there is something to report immediatly. 512737a1286SJulian Elischer */ 513737a1286SJulian Elischer if ((events & (POLLIN | POLLRDNORM))) { 514737a1286SJulian Elischer if (tp->t_iflag & ICANON) { 515737a1286SJulian Elischer if (tp->t_canq.c_cc) 516737a1286SJulian Elischer revents |= events & (POLLIN | POLLRDNORM); 517737a1286SJulian Elischer } else { 518737a1286SJulian Elischer if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 519737a1286SJulian Elischer revents |= events & (POLLIN | POLLRDNORM); 520737a1286SJulian Elischer } 521737a1286SJulian Elischer } 522737a1286SJulian Elischer 523737a1286SJulian Elischer /* 524737a1286SJulian Elischer * check if there is room in the other tty's input buffers. 525737a1286SJulian Elischer */ 526737a1286SJulian Elischer if ((events & (POLLOUT | POLLWRNORM)) 527737a1286SJulian Elischer && ((tp2->t_rawq.c_cc + tp2->t_canq.c_cc < TTYHOG - 2) 528737a1286SJulian Elischer || (tp2->t_canq.c_cc == 0 && (tp2->t_iflag & ICANON)))) { 529737a1286SJulian Elischer revents |= events & (POLLOUT | POLLWRNORM); 530737a1286SJulian Elischer } 531737a1286SJulian Elischer 532737a1286SJulian Elischer if (events & POLLHUP) 533737a1286SJulian Elischer if ((tp->t_state & TS_CARR_ON) == 0) 534737a1286SJulian Elischer revents |= POLLHUP; 535737a1286SJulian Elischer 536737a1286SJulian Elischer /* 537737a1286SJulian Elischer * If nothing immediate, set us to return when something IS found. 538737a1286SJulian Elischer */ 539737a1286SJulian Elischer if (revents == 0) { 540737a1286SJulian Elischer if (events & (POLLIN | POLLRDNORM)) 541737a1286SJulian Elischer selrecord(p, &tp->t_rsel); 542737a1286SJulian Elischer 543737a1286SJulian Elischer if (events & (POLLOUT | POLLWRNORM)) 544737a1286SJulian Elischer selrecord(p, &tp->t_wsel); 545737a1286SJulian Elischer } 546737a1286SJulian Elischer splx(s); 547737a1286SJulian Elischer 548737a1286SJulian Elischer return (revents); 549737a1286SJulian Elischer } 550737a1286SJulian Elischer 551737a1286SJulian Elischer /*ARGSUSED*/ 552737a1286SJulian Elischer static int 553737a1286SJulian Elischer nmdmioctl(dev, cmd, data, flag, p) 554737a1286SJulian Elischer dev_t dev; 555737a1286SJulian Elischer u_long cmd; 556737a1286SJulian Elischer caddr_t data; 557737a1286SJulian Elischer int flag; 558737a1286SJulian Elischer struct proc *p; 559737a1286SJulian Elischer { 560737a1286SJulian Elischer register struct tty *tp = dev->si_tty; 561737a1286SJulian Elischer struct nm_softc *pti = dev->si_drv1; 562737a1286SJulian Elischer int error, s; 563737a1286SJulian Elischer register struct tty *tp2; 564737a1286SJulian Elischer struct softpart *ourpart, *otherpart; 565737a1286SJulian Elischer 566737a1286SJulian Elischer s = spltty(); 567737a1286SJulian Elischer GETPARTS(tp, ourpart, otherpart); 568737a1286SJulian Elischer tp2 = &otherpart->nm_tty; 569737a1286SJulian Elischer 570737a1286SJulian Elischer error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 571737a1286SJulian Elischer if (error == ENOIOCTL) 572737a1286SJulian Elischer error = ttioctl(tp, cmd, data, flag); 573737a1286SJulian Elischer if (error == ENOIOCTL) { 574737a1286SJulian Elischer switch (cmd) { 575737a1286SJulian Elischer case TIOCSBRK: 576737a1286SJulian Elischer otherpart->gotbreak = 1; 577737a1286SJulian Elischer break; 578737a1286SJulian Elischer case TIOCCBRK: 579737a1286SJulian Elischer break; 580737a1286SJulian Elischer case TIOCSDTR: 581737a1286SJulian Elischer ourpart->modemsignals |= TIOCM_DTR; 582737a1286SJulian Elischer break; 583737a1286SJulian Elischer case TIOCCDTR: 584737a1286SJulian Elischer ourpart->modemsignals &= TIOCM_DTR; 585737a1286SJulian Elischer break; 586737a1286SJulian Elischer case TIOCMSET: 587737a1286SJulian Elischer ourpart->modemsignals = *(int *)data; 588737a1286SJulian Elischer otherpart->modemsignals = *(int *)data; 589737a1286SJulian Elischer break; 590737a1286SJulian Elischer case TIOCMBIS: 591737a1286SJulian Elischer ourpart->modemsignals |= *(int *)data; 592737a1286SJulian Elischer break; 593737a1286SJulian Elischer case TIOCMBIC: 594737a1286SJulian Elischer ourpart->modemsignals &= ~(*(int *)data); 595737a1286SJulian Elischer otherpart->modemsignals &= ~(*(int *)data); 596737a1286SJulian Elischer break; 597737a1286SJulian Elischer case TIOCMGET: 598737a1286SJulian Elischer *(int *)data = ourpart->modemsignals; 599737a1286SJulian Elischer break; 600737a1286SJulian Elischer case TIOCMSDTRWAIT: 601737a1286SJulian Elischer break; 602737a1286SJulian Elischer case TIOCMGDTRWAIT: 603737a1286SJulian Elischer *(int *)data = 0; 604737a1286SJulian Elischer break; 605737a1286SJulian Elischer case TIOCTIMESTAMP: 606737a1286SJulian Elischer case TIOCDCDTIMESTAMP: 607737a1286SJulian Elischer default: 608737a1286SJulian Elischer splx(s); 609737a1286SJulian Elischer error = ENOTTY; 610737a1286SJulian Elischer return (error); 611737a1286SJulian Elischer } 612737a1286SJulian Elischer error = 0; 613737a1286SJulian Elischer nmdm_crossover(pti, ourpart, otherpart); 614737a1286SJulian Elischer } 615737a1286SJulian Elischer splx(s); 616737a1286SJulian Elischer return (error); 617737a1286SJulian Elischer } 618737a1286SJulian Elischer 619737a1286SJulian Elischer static void 620737a1286SJulian Elischer nmdm_crossover(struct nm_softc *pti, 621737a1286SJulian Elischer struct softpart *ourpart, 622737a1286SJulian Elischer struct softpart *otherpart) 623737a1286SJulian Elischer { 624737a1286SJulian Elischer otherpart->modemsignals &= ~(TIOCM_CTS|TIOCM_CAR); 625737a1286SJulian Elischer if (ourpart->modemsignals & TIOCM_RTS) 626737a1286SJulian Elischer otherpart->modemsignals |= TIOCM_CTS; 627737a1286SJulian Elischer if (ourpart->modemsignals & TIOCM_DTR) 628737a1286SJulian Elischer otherpart->modemsignals |= TIOCM_CAR; 629737a1286SJulian Elischer } 630737a1286SJulian Elischer 631737a1286SJulian Elischer 632737a1286SJulian Elischer 633737a1286SJulian Elischer static void nmdm_drvinit __P((void *unused)); 634737a1286SJulian Elischer 635737a1286SJulian Elischer static void 636737a1286SJulian Elischer nmdm_drvinit(unused) 637737a1286SJulian Elischer void *unused; 638737a1286SJulian Elischer { 639737a1286SJulian Elischer cdevsw_add(&nmdm_cdevsw); 640737a1286SJulian Elischer /* XXX: Gross hack for DEVFS */ 641737a1286SJulian Elischer nmdminit(0); 642737a1286SJulian Elischer } 643737a1286SJulian Elischer 644737a1286SJulian Elischer SYSINIT(nmdmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,nmdm_drvinit,NULL) 645