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