| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1982, 1986, 1989, 1993 | |
| 3 | * The Regents of the University of California. All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * 3. All advertising materials mentioning features or use of this software | |
| 14 | * must display the following acknowledgement: | |
| 15 | * This product includes software developed by the University of | |
| 16 | * California, Berkeley and its contributors. | |
| 17 | * 4. Neither the name of the University nor the names of its contributors | |
| 18 | * may be used to endorse or promote products derived from this software | |
| 19 | * without specific prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 31 | * SUCH DAMAGE. | |
| 32 | * | |
| 33 | * $FreeBSD: src/sys/dev/nmdm/nmdm.c,v 1.5.2.1 2001/08/11 00:54:14 mp Exp $ | |
| e7b4468c | 34 | * $DragonFly: src/sys/dev/misc/nmdm/nmdm.c,v 1.16 2008/01/05 14:02:37 swildner Exp $ |
| 984263bc MD |
35 | */ |
| 36 | ||
| 37 | /* | |
| 38 | * Pseudo-nulmodem Driver | |
| 39 | */ | |
| 40 | #include "opt_compat.h" | |
| 41 | #include <sys/param.h> | |
| 42 | #include <sys/systm.h> | |
| 43 | #if defined(COMPAT_43) || defined(COMPAT_SUNOS) | |
| 44 | #include <sys/ioctl_compat.h> | |
| 45 | #endif | |
| 46 | #include <sys/proc.h> | |
| 895c1f85 | 47 | #include <sys/priv.h> |
| 08cb819d | 48 | #include <sys/thread2.h> |
| 984263bc MD |
49 | #include <sys/tty.h> |
| 50 | #include <sys/conf.h> | |
| 51 | #include <sys/fcntl.h> | |
| 52 | #include <sys/poll.h> | |
| 53 | #include <sys/kernel.h> | |
| 54 | #include <sys/vnode.h> | |
| 55 | #include <sys/signalvar.h> | |
| 56 | #include <sys/malloc.h> | |
| 57 | ||
| 58 | MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures"); | |
| 59 | ||
| 38e94a25 RG |
60 | static void nmdmstart (struct tty *tp); |
| 61 | static void nmdmstop (struct tty *tp, int rw); | |
| 62 | static void wakeup_other (struct tty *tp, int flag); | |
| 63 | static void nmdminit (int n); | |
| 984263bc MD |
64 | |
| 65 | static d_open_t nmdmopen; | |
| 66 | static d_close_t nmdmclose; | |
| 67 | static d_read_t nmdmread; | |
| 68 | static d_write_t nmdmwrite; | |
| 69 | static d_ioctl_t nmdmioctl; | |
| 70 | ||
| 71 | #define CDEV_MAJOR 18 | |
| fef8985e MD |
72 | static struct dev_ops nmdm_ops = { |
| 73 | { "pts", CDEV_MAJOR, D_TTY }, | |
| 74 | .d_open = nmdmopen, | |
| 75 | .d_close = nmdmclose, | |
| 76 | .d_read = nmdmread, | |
| 77 | .d_write = nmdmwrite, | |
| 78 | .d_ioctl = nmdmioctl, | |
| 79 | .d_poll = ttypoll, | |
| a32446b7 | 80 | .d_revoke = ttyrevoke |
| 984263bc MD |
81 | }; |
| 82 | ||
| 83 | #define BUFSIZ 100 /* Chunk size iomoved to/from user */ | |
| 84 | ||
| 85 | struct softpart { | |
| 86 | struct tty nm_tty; | |
| b13267a5 | 87 | cdev_t dev; |
| 984263bc MD |
88 | int modemsignals; /* bits defined in sys/ttycom.h */ |
| 89 | int gotbreak; | |
| 90 | }; | |
| 91 | ||
| 92 | struct nm_softc { | |
| 93 | int pt_flags; | |
| 94 | struct softpart part1, part2; | |
| 95 | struct prison *pt_prison; | |
| 96 | }; | |
| 97 | ||
| 98 | #define PF_STOPPED 0x10 /* user told stopped */ | |
| 99 | ||
| 100 | static void | |
| 101 | nmdm_crossover(struct nm_softc *pti, | |
| 102 | struct softpart *ourpart, | |
| 103 | struct softpart *otherpart); | |
| 104 | ||
| 105 | #define GETPARTS(tp, ourpart, otherpart) \ | |
| 106 | do { \ | |
| 107 | struct nm_softc *pti = tp->t_dev->si_drv1; \ | |
| 108 | if (tp == &pti->part1.nm_tty) { \ | |
| 109 | ourpart = &pti->part1; \ | |
| 110 | otherpart = &pti->part2; \ | |
| 111 | } else { \ | |
| 112 | ourpart = &pti->part2; \ | |
| 113 | otherpart = &pti->part1; \ | |
| 114 | } \ | |
| 115 | } while (0) | |
| 116 | ||
| 117 | /* | |
| 118 | * This function creates and initializes a pair of ttys. | |
| 119 | */ | |
| 120 | static void | |
| c436375a | 121 | nmdminit(int n) |
| 984263bc | 122 | { |
| b13267a5 | 123 | cdev_t dev1, dev2; |
| 984263bc MD |
124 | struct nm_softc *pt; |
| 125 | ||
| e4c9c0c8 MD |
126 | /* |
| 127 | * Simplified unit number, use low 8 bits of minor number | |
| 128 | * (remember, the minor number mask is 0xffff00ff). | |
| 129 | */ | |
| 130 | if (n & ~0x7f) | |
| 984263bc MD |
131 | return; |
| 132 | ||
| e7b4468c | 133 | pt = kmalloc(sizeof(*pt), M_NLMDM, M_WAITOK | M_ZERO); |
| fef8985e | 134 | pt->part1.dev = dev1 = make_dev(&nmdm_ops, n << 1, |
| 3e82b46c | 135 | 0, 0, 0666, "nmdm%dA", n); |
| fef8985e | 136 | pt->part2.dev = dev2 = make_dev(&nmdm_ops, (n << 1) + 1, |
| 3e82b46c | 137 | 0, 0, 0666, "nmdm%dB", n); |
| 984263bc MD |
138 | |
| 139 | dev1->si_drv1 = dev2->si_drv1 = pt; | |
| 140 | dev1->si_tty = &pt->part1.nm_tty; | |
| 141 | dev2->si_tty = &pt->part2.nm_tty; | |
| 142 | ttyregister(&pt->part1.nm_tty); | |
| 143 | ttyregister(&pt->part2.nm_tty); | |
| 144 | pt->part1.nm_tty.t_oproc = nmdmstart; | |
| 145 | pt->part2.nm_tty.t_oproc = nmdmstart; | |
| 146 | pt->part1.nm_tty.t_stop = nmdmstop; | |
| 147 | pt->part2.nm_tty.t_dev = dev1; | |
| 148 | pt->part1.nm_tty.t_dev = dev2; | |
| 149 | pt->part2.nm_tty.t_stop = nmdmstop; | |
| 150 | } | |
| 151 | ||
| 152 | /*ARGSUSED*/ | |
| 153 | static int | |
| fef8985e | 154 | nmdmopen(struct dev_open_args *ap) |
| 984263bc | 155 | { |
| b13267a5 | 156 | cdev_t dev = ap->a_head.a_dev; |
| 41c20dac | 157 | struct tty *tp, *tp2; |
| 984263bc MD |
158 | int error; |
| 159 | int minr; | |
| e4c9c0c8 | 160 | #if 0 |
| b13267a5 | 161 | cdev_t nextdev; |
| e4c9c0c8 | 162 | #endif |
| 984263bc MD |
163 | struct nm_softc *pti; |
| 164 | int is_b; | |
| 165 | int pair; | |
| 166 | struct softpart *ourpart, *otherpart; | |
| 167 | ||
| e4c9c0c8 MD |
168 | minr = lminor(dev); |
| 169 | pair = minr >> 1; | |
| 170 | is_b = minr & 1; | |
| 171 | ||
| 172 | #if 0 | |
| 984263bc MD |
173 | /* |
| 174 | * XXX: Gross hack for DEVFS: | |
| 175 | * If we openned this device, ensure we have the | |
| 176 | * next one too, so people can open it. | |
| 177 | */ | |
| 984263bc MD |
178 | if (pair < 127) { |
| 179 | nextdev = makedev(major(dev), (pair+pair) + 1); | |
| 180 | if (!nextdev->si_drv1) { | |
| 181 | nmdminit(pair + 1); | |
| 182 | } | |
| 183 | } | |
| e4c9c0c8 | 184 | #endif |
| 984263bc MD |
185 | if (!dev->si_drv1) |
| 186 | nmdminit(pair); | |
| 187 | ||
| 188 | if (!dev->si_drv1) | |
| 189 | return(ENXIO); | |
| 190 | ||
| 191 | pti = dev->si_drv1; | |
| 192 | if (is_b) | |
| 193 | tp = &pti->part2.nm_tty; | |
| 194 | else | |
| 195 | tp = &pti->part1.nm_tty; | |
| 196 | GETPARTS(tp, ourpart, otherpart); | |
| 197 | tp2 = &otherpart->nm_tty; | |
| 198 | ourpart->modemsignals |= TIOCM_LE; | |
| 199 | ||
| 200 | if ((tp->t_state & TS_ISOPEN) == 0) { | |
| 201 | ttychars(tp); /* Set up default chars */ | |
| 202 | tp->t_iflag = TTYDEF_IFLAG; | |
| 203 | tp->t_oflag = TTYDEF_OFLAG; | |
| 204 | tp->t_lflag = TTYDEF_LFLAG; | |
| 205 | tp->t_cflag = TTYDEF_CFLAG; | |
| 206 | tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; | |
| 895c1f85 | 207 | } else if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) { |
| 984263bc | 208 | return (EBUSY); |
| fef8985e | 209 | } else if (pti->pt_prison != ap->a_cred->cr_prison) { |
| 984263bc MD |
210 | return (EBUSY); |
| 211 | } | |
| 212 | ||
| 213 | /* | |
| 214 | * If the other side is open we have carrier | |
| 215 | */ | |
| 216 | if (tp2->t_state & TS_ISOPEN) { | |
| 217 | (void)(*linesw[tp->t_line].l_modem)(tp, 1); | |
| 218 | } | |
| 219 | ||
| 220 | /* | |
| 221 | * And the other side gets carrier as we are now open. | |
| 222 | */ | |
| 223 | (void)(*linesw[tp2->t_line].l_modem)(tp2, 1); | |
| 224 | ||
| 225 | /* External processing makes no sense here */ | |
| 226 | tp->t_lflag &= ~EXTPROC; | |
| 227 | ||
| 228 | /* | |
| 229 | * Wait here if we don't have carrier. | |
| 230 | */ | |
| 231 | #if 0 | |
| 232 | while ((tp->t_state & TS_CARR_ON) == 0) { | |
| 233 | if (flag & FNONBLOCK) | |
| 234 | break; | |
| 377d4740 | 235 | error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "nmdopn", 0); |
| 984263bc MD |
236 | if (error) |
| 237 | return (error); | |
| 238 | } | |
| 239 | #endif | |
| 240 | ||
| 241 | /* | |
| 242 | * Give the line disciplin a chance to set this end up. | |
| 243 | */ | |
| 244 | error = (*linesw[tp->t_line].l_open)(dev, tp); | |
| 245 | ||
| 246 | /* | |
| 247 | * Wake up the other side. | |
| 248 | * Theoretically not needed. | |
| 249 | */ | |
| 250 | ourpart->modemsignals |= TIOCM_DTR; | |
| 251 | nmdm_crossover(pti, ourpart, otherpart); | |
| 252 | if (error == 0) | |
| 253 | wakeup_other(tp, FREAD|FWRITE); /* XXX */ | |
| 254 | return (error); | |
| 255 | } | |
| 256 | ||
| fef8985e MD |
257 | static int |
| 258 | nmdmclose(struct dev_close_args *ap) | |
| 984263bc | 259 | { |
| b13267a5 | 260 | cdev_t dev = ap->a_head.a_dev; |
| f96d6c88 | 261 | struct tty *tp, *tp2; |
| 984263bc MD |
262 | int err; |
| 263 | struct softpart *ourpart, *otherpart; | |
| 264 | ||
| 265 | /* | |
| 266 | * let the other end know that the game is up | |
| 267 | */ | |
| 268 | tp = dev->si_tty; | |
| 269 | GETPARTS(tp, ourpart, otherpart); | |
| 270 | tp2 = &otherpart->nm_tty; | |
| 271 | (void)(*linesw[tp2->t_line].l_modem)(tp2, 0); | |
| 272 | ||
| 273 | /* | |
| 274 | * XXX MDMBUF makes no sense for nmdms but would inhibit the above | |
| 275 | * l_modem(). CLOCAL makes sense but isn't supported. Special | |
| 276 | * l_modem()s that ignore carrier drop make no sense for nmdms but | |
| 277 | * may be in use because other parts of the line discipline make | |
| 278 | * sense for nmdms. Recover by doing everything that a normal | |
| 279 | * ttymodem() would have done except for sending a SIGHUP. | |
| 280 | */ | |
| 281 | if (tp2->t_state & TS_ISOPEN) { | |
| 282 | tp2->t_state &= ~(TS_CARR_ON | TS_CONNECTED); | |
| 283 | tp2->t_state |= TS_ZOMBIE; | |
| 284 | ttyflush(tp2, FREAD | FWRITE); | |
| 285 | } | |
| 286 | ||
| fef8985e | 287 | err = (*linesw[tp->t_line].l_close)(tp, ap->a_fflag); |
| 984263bc MD |
288 | ourpart->modemsignals &= ~TIOCM_DTR; |
| 289 | nmdm_crossover(dev->si_drv1, ourpart, otherpart); | |
| 290 | nmdmstop(tp, FREAD|FWRITE); | |
| 291 | (void) ttyclose(tp); | |
| 292 | return (err); | |
| 293 | } | |
| 294 | ||
| fef8985e MD |
295 | static int |
| 296 | nmdmread(struct dev_read_args *ap) | |
| 984263bc | 297 | { |
| b13267a5 | 298 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
299 | int error = 0; |
| 300 | struct tty *tp, *tp2; | |
| 301 | struct softpart *ourpart, *otherpart; | |
| 302 | ||
| 303 | tp = dev->si_tty; | |
| 304 | GETPARTS(tp, ourpart, otherpart); | |
| 305 | tp2 = &otherpart->nm_tty; | |
| 306 | ||
| 307 | #if 0 | |
| 308 | if (tp2->t_state & TS_ISOPEN) { | |
| fef8985e | 309 | error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, flag); |
| 984263bc MD |
310 | wakeup_other(tp, FWRITE); |
| 311 | } else { | |
| 312 | if (flag & IO_NDELAY) { | |
| 313 | return (EWOULDBLOCK); | |
| 314 | } | |
| 377d4740 | 315 | error = tsleep(TSA_PTC_READ(tp), PCATCH, "nmdout", 0); |
| 984263bc MD |
316 | } |
| 317 | } | |
| 318 | #else | |
| fef8985e | 319 | if ((error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag)) == 0) |
| 984263bc MD |
320 | wakeup_other(tp, FWRITE); |
| 321 | #endif | |
| 322 | return (error); | |
| 323 | } | |
| 324 | ||
| 325 | /* | |
| 326 | * Write to pseudo-tty. | |
| 327 | * Wakeups of controlling tty will happen | |
| 328 | * indirectly, when tty driver calls nmdmstart. | |
| 329 | */ | |
| 330 | static int | |
| fef8985e | 331 | nmdmwrite(struct dev_write_args *ap) |
| 984263bc | 332 | { |
| b13267a5 | 333 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 334 | struct uio *uio = ap->a_uio; |
| f96d6c88 RG |
335 | u_char *cp = 0; |
| 336 | int cc = 0; | |
| 984263bc MD |
337 | u_char locbuf[BUFSIZ]; |
| 338 | int cnt = 0; | |
| 339 | int error = 0; | |
| 340 | struct tty *tp1, *tp; | |
| 341 | struct softpart *ourpart, *otherpart; | |
| 342 | ||
| 343 | tp1 = dev->si_tty; | |
| 344 | /* | |
| 345 | * Get the other tty struct. | |
| 346 | * basically we are writing into the INPUT side of the other device. | |
| 347 | */ | |
| 348 | GETPARTS(tp1, ourpart, otherpart); | |
| 349 | tp = &otherpart->nm_tty; | |
| 350 | ||
| 351 | again: | |
| 352 | if ((tp->t_state & TS_ISOPEN) == 0) | |
| 353 | return (EIO); | |
| 354 | while (uio->uio_resid > 0 || cc > 0) { | |
| 355 | /* | |
| 356 | * Fill up the buffer if it's empty | |
| 357 | */ | |
| 358 | if (cc == 0) { | |
| 359 | cc = min(uio->uio_resid, BUFSIZ); | |
| 360 | cp = locbuf; | |
| 361 | error = uiomove((caddr_t)cp, cc, uio); | |
| 362 | if (error) | |
| 363 | return (error); | |
| 364 | /* check again for safety */ | |
| 365 | if ((tp->t_state & TS_ISOPEN) == 0) { | |
| 366 | /* adjust for data copied in but not written */ | |
| 367 | uio->uio_resid += cc; | |
| 368 | return (EIO); | |
| 369 | } | |
| 370 | } | |
| 371 | while (cc > 0) { | |
| 372 | if (((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= (TTYHOG-2)) | |
| 373 | && ((tp->t_canq.c_cc > 0) || !(tp->t_iflag&ICANON))) { | |
| 374 | /* | |
| 375 | * Come here to wait for space in outq, | |
| 376 | * or space in rawq, or an empty canq. | |
| 377 | */ | |
| 378 | wakeup(TSA_HUP_OR_INPUT(tp)); | |
| 379 | if ((tp->t_state & TS_CONNECTED) == 0) { | |
| 380 | /* | |
| 381 | * Data piled up because not connected. | |
| 382 | * Adjust for data copied in but | |
| 383 | * not written. | |
| 384 | */ | |
| 385 | uio->uio_resid += cc; | |
| 386 | return (EIO); | |
| 387 | } | |
| fef8985e | 388 | if (ap->a_ioflag & IO_NDELAY) { |
| 984263bc MD |
389 | /* |
| 390 | * Don't wait if asked not to. | |
| 391 | * Adjust for data copied in but | |
| 392 | * not written. | |
| 393 | */ | |
| 394 | uio->uio_resid += cc; | |
| 395 | if (cnt == 0) | |
| 396 | return (EWOULDBLOCK); | |
| 397 | return (0); | |
| 398 | } | |
| 399 | error = tsleep(TSA_PTC_WRITE(tp), | |
| 377d4740 | 400 | PCATCH, "nmdout", 0); |
| 984263bc MD |
401 | if (error) { |
| 402 | /* | |
| 403 | * Tsleep returned (signal?). | |
| 404 | * Go find out what the user wants. | |
| 405 | * adjust for data copied in but | |
| 406 | * not written | |
| 407 | */ | |
| 408 | uio->uio_resid += cc; | |
| 409 | return (error); | |
| 410 | } | |
| 411 | goto again; | |
| 412 | } | |
| 413 | (*linesw[tp->t_line].l_rint)(*cp++, tp); | |
| 414 | cnt++; | |
| 415 | cc--; | |
| 416 | } | |
| 417 | cc = 0; | |
| 418 | } | |
| 419 | return (0); | |
| 420 | } | |
| 421 | ||
| 422 | /* | |
| 423 | * Start output on pseudo-tty. | |
| 424 | * Wake up process selecting or sleeping for input from controlling tty. | |
| 425 | */ | |
| 426 | static void | |
| c436375a | 427 | nmdmstart(struct tty *tp) |
| 984263bc | 428 | { |
| f96d6c88 | 429 | struct nm_softc *pti = tp->t_dev->si_drv1; |
| 984263bc MD |
430 | |
| 431 | if (tp->t_state & TS_TTSTOP) | |
| 432 | return; | |
| 433 | pti->pt_flags &= ~PF_STOPPED; | |
| 434 | wakeup_other(tp, FREAD); | |
| 435 | } | |
| 436 | ||
| 437 | /* Wakes up the OTHER tty;*/ | |
| 438 | static void | |
| c436375a | 439 | wakeup_other(struct tty *tp, int flag) |
| 984263bc MD |
440 | { |
| 441 | struct softpart *ourpart, *otherpart; | |
| 442 | ||
| 443 | GETPARTS(tp, ourpart, otherpart); | |
| 444 | if (flag & FREAD) { | |
| 445 | selwakeup(&otherpart->nm_tty.t_rsel); | |
| 446 | wakeup(TSA_PTC_READ((&otherpart->nm_tty))); | |
| 447 | } | |
| 448 | if (flag & FWRITE) { | |
| 449 | selwakeup(&otherpart->nm_tty.t_wsel); | |
| 450 | wakeup(TSA_PTC_WRITE((&otherpart->nm_tty))); | |
| 451 | } | |
| 452 | } | |
| 453 | ||
| 454 | static void | |
| c436375a | 455 | nmdmstop(struct tty *tp, int flush) |
| 984263bc MD |
456 | { |
| 457 | struct nm_softc *pti = tp->t_dev->si_drv1; | |
| 458 | int flag; | |
| 459 | ||
| 460 | /* note: FLUSHREAD and FLUSHWRITE already ok */ | |
| 461 | if (flush == 0) { | |
| 462 | flush = TIOCPKT_STOP; | |
| 463 | pti->pt_flags |= PF_STOPPED; | |
| 464 | } else | |
| 465 | pti->pt_flags &= ~PF_STOPPED; | |
| 466 | /* change of perspective */ | |
| 467 | flag = 0; | |
| 468 | if (flush & FREAD) | |
| 469 | flag |= FWRITE; | |
| 470 | if (flush & FWRITE) | |
| 471 | flag |= FREAD; | |
| 472 | wakeup_other(tp, flag); | |
| 473 | } | |
| 474 | ||
| 475 | /*ARGSUSED*/ | |
| 476 | static int | |
| fef8985e | 477 | nmdmioctl(struct dev_ioctl_args *ap) |
| 984263bc | 478 | { |
| b13267a5 | 479 | cdev_t dev = ap->a_head.a_dev; |
| f96d6c88 | 480 | struct tty *tp = dev->si_tty; |
| 984263bc | 481 | struct nm_softc *pti = dev->si_drv1; |
| 08cb819d | 482 | int error; |
| f96d6c88 | 483 | struct tty *tp2; |
| 984263bc MD |
484 | struct softpart *ourpart, *otherpart; |
| 485 | ||
| 08cb819d | 486 | crit_enter(); |
| 984263bc MD |
487 | GETPARTS(tp, ourpart, otherpart); |
| 488 | tp2 = &otherpart->nm_tty; | |
| 489 | ||
| fef8985e MD |
490 | error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data, |
| 491 | ap->a_fflag, ap->a_cred); | |
| 984263bc | 492 | if (error == ENOIOCTL) |
| fef8985e | 493 | error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag); |
| 984263bc | 494 | if (error == ENOIOCTL) { |
| fef8985e | 495 | switch (ap->a_cmd) { |
| 984263bc MD |
496 | case TIOCSBRK: |
| 497 | otherpart->gotbreak = 1; | |
| 498 | break; | |
| 499 | case TIOCCBRK: | |
| 500 | break; | |
| 501 | case TIOCSDTR: | |
| 502 | ourpart->modemsignals |= TIOCM_DTR; | |
| 503 | break; | |
| 504 | case TIOCCDTR: | |
| 505 | ourpart->modemsignals &= TIOCM_DTR; | |
| 506 | break; | |
| 507 | case TIOCMSET: | |
| fef8985e MD |
508 | ourpart->modemsignals = *(int *)ap->a_data; |
| 509 | otherpart->modemsignals = *(int *)ap->a_data; | |
| 984263bc MD |
510 | break; |
| 511 | case TIOCMBIS: | |
| fef8985e | 512 | ourpart->modemsignals |= *(int *)ap->a_data; |
| 984263bc MD |
513 | break; |
| 514 | case TIOCMBIC: | |
| fef8985e MD |
515 | ourpart->modemsignals &= ~(*(int *)ap->a_data); |
| 516 | otherpart->modemsignals &= ~(*(int *)ap->a_data); | |
| 984263bc MD |
517 | break; |
| 518 | case TIOCMGET: | |
| fef8985e | 519 | *(int *)ap->a_data = ourpart->modemsignals; |
| 984263bc MD |
520 | break; |
| 521 | case TIOCMSDTRWAIT: | |
| 522 | break; | |
| 523 | case TIOCMGDTRWAIT: | |
| fef8985e | 524 | *(int *)ap->a_data = 0; |
| 984263bc MD |
525 | break; |
| 526 | case TIOCTIMESTAMP: | |
| 527 | case TIOCDCDTIMESTAMP: | |
| 528 | default: | |
| 08cb819d | 529 | crit_exit(); |
| 984263bc MD |
530 | error = ENOTTY; |
| 531 | return (error); | |
| 532 | } | |
| 533 | error = 0; | |
| 534 | nmdm_crossover(pti, ourpart, otherpart); | |
| 535 | } | |
| 08cb819d | 536 | crit_exit(); |
| 984263bc MD |
537 | return (error); |
| 538 | } | |
| 539 | ||
| 540 | static void | |
| 541 | nmdm_crossover(struct nm_softc *pti, | |
| 542 | struct softpart *ourpart, | |
| 543 | struct softpart *otherpart) | |
| 544 | { | |
| 545 | otherpart->modemsignals &= ~(TIOCM_CTS|TIOCM_CAR); | |
| 546 | if (ourpart->modemsignals & TIOCM_RTS) | |
| 547 | otherpart->modemsignals |= TIOCM_CTS; | |
| 548 | if (ourpart->modemsignals & TIOCM_DTR) | |
| 549 | otherpart->modemsignals |= TIOCM_CAR; | |
| 550 | } | |
| 551 | ||
| 552 | ||
| 553 | ||
| 38e94a25 | 554 | static void nmdm_drvinit (void *unused); |
| 984263bc MD |
555 | |
| 556 | static void | |
| c436375a | 557 | nmdm_drvinit(void *unused) |
| 984263bc | 558 | { |
| 984263bc MD |
559 | /* XXX: Gross hack for DEVFS */ |
| 560 | nmdminit(0); | |
| 561 | } | |
| 562 | ||
| 563 | SYSINIT(nmdmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,nmdm_drvinit,NULL) |