dhcpcd.conf.5/swapon.8: Fix some typos.
[dragonfly.git] / sys / dev / misc / nmdm / nmdm.c
1 /*
2  * (MPSAFE)
3  *
4  * Copyright (c) 1982, 1986, 1989, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
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.
18  *
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.
30  *
31  * $FreeBSD: src/sys/dev/nmdm/nmdm.c,v 1.5.2.1 2001/08/11 00:54:14 mp Exp $
32  */
33
34 /*
35  * Pseudo-nulmodem Driver
36  */
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/proc.h>
40 #include <sys/priv.h>
41 #include <sys/tty.h>
42 #include <sys/ttydefaults.h>    /* for TTYDEF_* */
43 #include <sys/conf.h>
44 #include <sys/fcntl.h>
45 #include <sys/kernel.h>
46 #include <sys/vnode.h>
47 #include <sys/signalvar.h>
48 #include <sys/malloc.h>
49
50 MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures");
51
52 static void nmdmstart (struct tty *tp);
53 static void nmdmstop (struct tty *tp, int rw);
54 static void wakeup_other (struct tty *tp, int flag);
55 static void nmdminit (int n);
56
57 static  d_open_t        nmdmopen;
58 static  d_close_t       nmdmclose;
59 static  d_read_t        nmdmread;
60 static  d_write_t       nmdmwrite;
61 static  d_ioctl_t       nmdmioctl;
62
63 #define CDEV_MAJOR      18
64 static struct dev_ops nmdm_ops = {
65         { "pts", 0, D_TTY },
66         .d_open =       nmdmopen,
67         .d_close =      nmdmclose,
68         .d_read =       nmdmread,
69         .d_write =      nmdmwrite,
70         .d_ioctl =      nmdmioctl,
71         .d_kqfilter =   ttykqfilter,
72         .d_revoke =     ttyrevoke
73 };
74
75 #define BUFSIZ 100              /* Chunk size iomoved to/from user */
76
77 struct softpart {
78         struct tty nm_tty;
79         cdev_t  dev;
80         int     modemsignals;   /* bits defined in sys/ttycom.h */
81         int     gotbreak;
82 };
83
84 struct  nm_softc {
85         int     pt_flags;
86         struct softpart part1, part2;
87         struct  prison *pt_prison;
88 };
89
90 #define PF_STOPPED      0x10            /* user told stopped */
91
92 static void
93 nmdm_crossover(struct nm_softc *pti,
94                 struct softpart *ourpart,
95                 struct softpart *otherpart);
96
97 #define GETPARTS(tp, ourpart, otherpart) \
98 do {    \
99         struct nm_softc *pti = tp->t_dev->si_drv1; \
100         if (tp == &pti->part1.nm_tty) { \
101                 ourpart = &pti->part1; \
102                 otherpart = &pti->part2; \
103         } else { \
104                 ourpart = &pti->part2; \
105                 otherpart = &pti->part1; \
106         }  \
107 } while (0)
108
109 /*
110  * This function creates and initializes a pair of ttys.
111  */
112 static void
113 nmdminit(int n)
114 {
115         cdev_t dev1, dev2;
116         struct nm_softc *pt;
117
118         /*
119          * Simplified unit number, use low 8 bits of minor number
120          * (remember, the minor number mask is 0xffff00ff).
121          */
122         if (n & ~0x7f)
123                 return;
124
125         pt = kmalloc(sizeof(*pt), M_NLMDM, M_WAITOK | M_ZERO);
126         pt->part1.dev = dev1 = make_dev(&nmdm_ops, n << 1,
127                                         0, 0, 0666, "nmdm%dA", n);
128         pt->part2.dev = dev2 = make_dev(&nmdm_ops, (n << 1) + 1,
129                                         0, 0, 0666, "nmdm%dB", n);
130
131         dev1->si_drv1 = dev2->si_drv1 = pt;
132         dev1->si_tty = &pt->part1.nm_tty;
133         dev2->si_tty = &pt->part2.nm_tty;
134         ttyinit(&pt->part1.nm_tty);
135         ttyinit(&pt->part2.nm_tty);
136         ttyregister(&pt->part1.nm_tty);
137         ttyregister(&pt->part2.nm_tty);
138         pt->part1.nm_tty.t_oproc = nmdmstart;
139         pt->part2.nm_tty.t_oproc = nmdmstart;
140         pt->part1.nm_tty.t_stop = nmdmstop;
141         pt->part2.nm_tty.t_dev = dev1;
142         pt->part1.nm_tty.t_dev = dev2;
143         pt->part2.nm_tty.t_stop = nmdmstop;
144 }
145
146 /*ARGSUSED*/
147 static  int
148 nmdmopen(struct dev_open_args *ap)
149 {
150         cdev_t dev = ap->a_head.a_dev;
151         struct tty *tp, *tp2;
152         int error;
153         int minr;
154 #if 0
155         cdev_t nextdev;
156 #endif
157         struct nm_softc *pti;
158         int is_b;
159         int     pair;
160         struct  softpart *ourpart, *otherpart;
161
162         minr = lminor(dev);
163         pair = minr >> 1;
164         is_b = minr & 1;
165         
166 #if 0
167         /*
168          * XXX: Gross hack for DEVFS:
169          * If we openned this device, ensure we have the
170          * next one too, so people can open it.
171          */
172         if (pair < 127) {
173                 nextdev = makedev(major(dev), (pair+pair) + 1);
174                 if (!nextdev->si_drv1) {
175                         nmdminit(pair + 1);
176                 }
177         }
178 #endif
179         if (!dev->si_drv1)
180                 nmdminit(pair);
181
182         if (!dev->si_drv1)
183                 return(ENXIO);  
184
185         pti = dev->si_drv1;
186         if (is_b) 
187                 tp = &pti->part2.nm_tty;
188         else 
189                 tp = &pti->part1.nm_tty;
190         lwkt_gettoken(&tp->t_token);
191         GETPARTS(tp, ourpart, otherpart);
192         tp2 = &otherpart->nm_tty;
193         lwkt_gettoken(&tp2->t_token);
194         ourpart->modemsignals |= TIOCM_LE;
195
196         if ((tp->t_state & TS_ISOPEN) == 0) {
197                 ttychars(tp);           /* Set up default chars */
198                 tp->t_iflag = TTYDEF_IFLAG;
199                 tp->t_oflag = TTYDEF_OFLAG;
200                 tp->t_lflag = TTYDEF_LFLAG;
201                 tp->t_cflag = TTYDEF_CFLAG;
202                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
203         } else if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
204                 lwkt_reltoken(&tp2->t_token);
205                 lwkt_reltoken(&tp->t_token);
206
207                 return (EBUSY);
208         } else if (pti->pt_prison != ap->a_cred->cr_prison) {
209                 lwkt_reltoken(&tp2->t_token);
210                 lwkt_reltoken(&tp->t_token);
211
212                 return (EBUSY);
213         }
214
215         /*
216          * If the other side is open we have carrier
217          */
218         if (tp2->t_state & TS_ISOPEN) {
219                 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
220         }
221
222         /*
223          * And the other side gets carrier as we are now open.
224          */
225         (void)(*linesw[tp2->t_line].l_modem)(tp2, 1);
226
227         /* External processing makes no sense here */
228         tp->t_lflag &= ~EXTPROC;
229
230         /* 
231          * Wait here if we don't have carrier.
232          */
233 #if 0
234         while ((tp->t_state & TS_CARR_ON) == 0) {
235                 if (flag & FNONBLOCK)
236                         break;
237                 error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "nmdopn", 0);
238                 if (error) {
239                         lwkt_reltoken(&tp2->t_token);
240                         lwkt_reltoken(&tp->t_token);
241
242                         return (error);
243                 }
244         }
245 #endif
246
247         /*
248          * Give the line disciplin a chance to set this end up.
249          */
250         error = (*linesw[tp->t_line].l_open)(dev, tp);
251
252         /*
253          * Wake up the other side.
254          * Theoretically not needed.
255          */
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(&tp2->t_token);
261         lwkt_reltoken(&tp->t_token);
262
263         return (error);
264 }
265
266 static int
267 nmdmclose(struct dev_close_args *ap)
268 {
269         cdev_t dev = ap->a_head.a_dev;
270         struct tty *tp, *tp2;
271         int err;
272         struct softpart *ourpart, *otherpart;
273
274         /*
275          * let the other end know that the game is up
276          */
277         tp = dev->si_tty;
278         lwkt_gettoken(&tp->t_token);
279         GETPARTS(tp, ourpart, otherpart);
280         tp2 = &otherpart->nm_tty;
281         lwkt_gettoken(&tp2->t_token);
282         (void)(*linesw[tp2->t_line].l_modem)(tp2, 0);
283
284         /*
285          * XXX MDMBUF makes no sense for nmdms but would inhibit the above
286          * l_modem().  CLOCAL makes sense but isn't supported.   Special
287          * l_modem()s that ignore carrier drop make no sense for nmdms but
288          * may be in use because other parts of the line discipline make
289          * sense for nmdms.  Recover by doing everything that a normal
290          * ttymodem() would have done except for sending a SIGHUP.
291          */
292         if (tp2->t_state & TS_ISOPEN) {
293                 tp2->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
294                 tp2->t_state |= TS_ZOMBIE;
295                 ttyflush(tp2, FREAD | FWRITE);
296         }
297
298         err = (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
299         ourpart->modemsignals &= ~TIOCM_DTR;
300         nmdm_crossover(dev->si_drv1, ourpart, otherpart);
301         nmdmstop(tp, FREAD|FWRITE);
302         ttyclose(tp);
303         lwkt_reltoken(&tp2->t_token);
304         lwkt_reltoken(&tp->t_token);
305
306         return (err);
307 }
308
309 static int
310 nmdmread(struct dev_read_args *ap)
311 {
312         cdev_t dev = ap->a_head.a_dev;
313         int error = 0;
314         struct tty *tp;
315 #if 0
316         struct tty *tp2;
317         struct softpart *ourpart, *otherpart;
318 #endif
319
320         tp = dev->si_tty;
321         lwkt_gettoken(&tp->t_token);
322 #if 0
323         GETPARTS(tp, ourpart, otherpart);
324         tp2 = &otherpart->nm_tty;
325         lwkt_gettoken(&tp2->t_token);
326
327         if (tp2->t_state & TS_ISOPEN) {
328                 error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, flag);
329                 wakeup_other(tp, FWRITE);
330         } else {
331                 if (flag & IO_NDELAY) {
332                         lwkt_reltoken(&tp2->t_token);
333                         lwkt_reltoken(&tp->t_token);
334                         return (EWOULDBLOCK);
335                 }
336                 error = tsleep(TSA_PTC_READ(tp), PCATCH, "nmdout", 0);
337                 }
338         }
339         lwkt_reltoken(&tp2->t_token);
340 #else
341         if ((error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag)) == 0)
342                 wakeup_other(tp, FWRITE);
343 #endif
344         lwkt_reltoken(&tp->t_token);
345
346         return (error);
347 }
348
349 /*
350  * Write to pseudo-tty.
351  * Wakeups of controlling tty will happen
352  * indirectly, when tty driver calls nmdmstart.
353  */
354 static  int
355 nmdmwrite(struct dev_write_args *ap)
356 {
357         cdev_t dev = ap->a_head.a_dev;
358         struct uio *uio = ap->a_uio;
359         u_char *cp = NULL;
360         size_t cc = 0;
361         u_char locbuf[BUFSIZ];
362         int cnt = 0;
363         int error = 0;
364         struct tty *tp1, *tp;
365         struct softpart *ourpart, *otherpart;
366
367         tp1 = dev->si_tty;
368         lwkt_gettoken(&tp1->t_token);
369         /*
370          * Get the other tty struct.
371          * basically we are writing into the INPUT side of the other device.
372          */
373         GETPARTS(tp1, ourpart, otherpart);
374         tp = &otherpart->nm_tty;
375         lwkt_gettoken(&tp->t_token);
376
377 again:
378         if ((tp->t_state & TS_ISOPEN) == 0) {
379                 lwkt_reltoken(&tp->t_token);
380                 lwkt_reltoken(&tp1->t_token);
381                 return (EIO);
382         }
383         while (uio->uio_resid > 0 || cc > 0) {
384                 /*
385                  * Fill up the buffer if it's empty
386                  */
387                 if (cc == 0) {
388                         cc = szmin(uio->uio_resid, BUFSIZ);
389                         cp = locbuf;
390                         error = uiomove((caddr_t)cp, cc, uio);
391                         if (error) {
392                                 lwkt_reltoken(&tp->t_token);
393                                 lwkt_reltoken(&tp1->t_token);
394                                 return (error);
395                         }
396                         /* check again for safety */
397                         if ((tp->t_state & TS_ISOPEN) == 0) {
398                                 /* adjust for data copied in but not written */
399                                 uio->uio_resid += cc;
400                                 lwkt_reltoken(&tp->t_token);
401                                 lwkt_reltoken(&tp1->t_token);
402                                 return (EIO);
403                         }
404                 }
405                 while (cc > 0) {
406                         if (((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= (TTYHOG-2))
407                         && ((tp->t_canq.c_cc > 0) || !(tp->t_iflag&ICANON))) {
408                                 /*
409                                  * Come here to wait for space in outq,
410                                  * or space in rawq, or an empty canq.
411                                  */
412                                 wakeup(TSA_HUP_OR_INPUT(tp));
413                                 if ((tp->t_state & TS_CONNECTED) == 0) {
414                                         /*
415                                          * Data piled up because not connected.
416                                          * Adjust for data copied in but
417                                          * not written.
418                                          */
419                                         uio->uio_resid += cc;
420                                         lwkt_reltoken(&tp->t_token);
421                                         lwkt_reltoken(&tp1->t_token);
422                                         return (EIO);
423                                 }
424                                 if (ap->a_ioflag & IO_NDELAY) {
425                                         /*
426                                          * Don't wait if asked not to.
427                                          * Adjust for data copied in but
428                                          * not written.
429                                          */
430                                         uio->uio_resid += cc;
431                                         if (cnt == 0) {
432                                                 lwkt_reltoken(&tp->t_token);
433                                                 lwkt_reltoken(&tp1->t_token);
434                                                 return (EWOULDBLOCK);
435                                         }
436                                         lwkt_reltoken(&tp->t_token);
437                                         lwkt_reltoken(&tp1->t_token);
438                                         return (0);
439                                 }
440                                 error = tsleep(TSA_PTC_WRITE(tp),
441                                                 PCATCH, "nmdout", 0);
442                                 if (error) {
443                                         /*
444                                          * Tsleep returned (signal?).
445                                          * Go find out what the user wants.
446                                          * adjust for data copied in but
447                                          * not written
448                                          */
449                                         uio->uio_resid += cc;
450                                         lwkt_reltoken(&tp->t_token);
451                                         lwkt_reltoken(&tp1->t_token);
452                                         return (error);
453                                 }
454                                 goto again;
455                         }
456                         (*linesw[tp->t_line].l_rint)(*cp++, tp);
457                         cnt++;
458                         cc--;
459                 }
460                 cc = 0;
461         }
462         lwkt_reltoken(&tp->t_token);
463         lwkt_reltoken(&tp1->t_token);
464
465         return (0);
466 }
467
468 /*
469  * Start output on pseudo-tty.
470  * Wake up process selecting or sleeping for input from controlling tty.
471  */
472 static void
473 nmdmstart(struct tty *tp)
474 {
475         struct nm_softc *pti = tp->t_dev->si_drv1;
476
477         lwkt_gettoken(&tp->t_token);
478         if (tp->t_state & TS_TTSTOP) {
479                 lwkt_reltoken(&tp->t_token);
480                 return;
481         }
482         pti->pt_flags &= ~PF_STOPPED;
483         wakeup_other(tp, FREAD);
484         lwkt_reltoken(&tp->t_token);
485 }
486
487 /*
488  * Wakes up the OTHER tty.  Caller must hold at least tp->t_token.
489  */
490 static void
491 wakeup_other(struct tty *tp, int flag)
492 {
493         struct softpart *ourpart, *otherpart;
494
495         GETPARTS(tp, ourpart, otherpart);
496         lwkt_gettoken(&otherpart->nm_tty.t_token);
497         if (flag & FREAD) {
498                 wakeup(TSA_PTC_READ((&otherpart->nm_tty)));
499                 KNOTE(&otherpart->nm_tty.t_rkq.ki_note, 0);
500         }
501         if (flag & FWRITE) {
502                 wakeup(TSA_PTC_WRITE((&otherpart->nm_tty)));
503                 KNOTE(&otherpart->nm_tty.t_wkq.ki_note, 0);
504         }
505         lwkt_reltoken(&otherpart->nm_tty.t_token);
506 }
507
508 static  void
509 nmdmstop(struct tty *tp, int flush)
510 {
511         struct nm_softc *pti = tp->t_dev->si_drv1;
512         int flag;
513
514         lwkt_gettoken(&tp->t_token);
515         /* note: FLUSHREAD and FLUSHWRITE already ok */
516         if (flush == 0) {
517                 flush = TIOCPKT_STOP;
518                 pti->pt_flags |= PF_STOPPED;
519         } else
520                 pti->pt_flags &= ~PF_STOPPED;
521         /* change of perspective */
522         flag = 0;
523         if (flush & FREAD)
524                 flag |= FWRITE;
525         if (flush & FWRITE)
526                 flag |= FREAD;
527         wakeup_other(tp, flag);
528         lwkt_reltoken(&tp->t_token);
529 }
530
531 /*ARGSUSED*/
532 static  int
533 nmdmioctl(struct dev_ioctl_args *ap)
534 {
535         cdev_t dev = ap->a_head.a_dev;
536         struct tty *tp = dev->si_tty;
537         struct tty *tp2;
538         struct nm_softc *pti = dev->si_drv1;
539         int error;
540         struct softpart *ourpart, *otherpart;
541
542         lwkt_gettoken(&tp->t_token);
543         GETPARTS(tp, ourpart, otherpart);
544         tp2 = &otherpart->nm_tty;
545         lwkt_gettoken(&tp2->t_token);
546
547         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
548                                               ap->a_fflag, ap->a_cred);
549         if (error == ENOIOCTL)
550                  error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
551         if (error == ENOIOCTL) {
552                 switch (ap->a_cmd) {
553                 case TIOCSBRK:
554                         otherpart->gotbreak = 1;
555                         break;
556                 case TIOCCBRK:
557                         break;
558                 case TIOCSDTR:
559                         ourpart->modemsignals |= TIOCM_DTR;
560                         break;
561                 case TIOCCDTR:
562                         ourpart->modemsignals &= TIOCM_DTR;
563                         break;
564                 case TIOCMSET:
565                         ourpart->modemsignals = *(int *)ap->a_data;
566                         otherpart->modemsignals = *(int *)ap->a_data;
567                         break;
568                 case TIOCMBIS:
569                         ourpart->modemsignals |= *(int *)ap->a_data;
570                         break;
571                 case TIOCMBIC:
572                         ourpart->modemsignals &= ~(*(int *)ap->a_data);
573                         otherpart->modemsignals &= ~(*(int *)ap->a_data);
574                         break;
575                 case TIOCMGET:
576                         *(int *)ap->a_data = ourpart->modemsignals;
577                         break;
578                 case TIOCMSDTRWAIT:
579                         break;
580                 case TIOCMGDTRWAIT:
581                         *(int *)ap->a_data = 0;
582                         break;
583                 case TIOCTIMESTAMP:
584                 case TIOCDCDTIMESTAMP:
585                 default:
586                         lwkt_reltoken(&tp2->t_token);
587                         lwkt_reltoken(&tp->t_token);
588                         error = ENOTTY;
589                         return (error);
590                 }
591                 error = 0;
592                 nmdm_crossover(pti, ourpart, otherpart);
593         }
594         lwkt_reltoken(&tp2->t_token);
595         lwkt_reltoken(&tp->t_token);
596
597         return (error);
598 }
599
600 /*
601  * Caller must hold both tty tokens
602  */
603 static void
604 nmdm_crossover(struct nm_softc *pti,
605                 struct softpart *ourpart,
606                 struct softpart *otherpart)
607 {
608         otherpart->modemsignals &= ~(TIOCM_CTS|TIOCM_CAR);
609         if (ourpart->modemsignals & TIOCM_RTS)
610                 otherpart->modemsignals |= TIOCM_CTS;
611         if (ourpart->modemsignals & TIOCM_DTR)
612                 otherpart->modemsignals |= TIOCM_CAR;
613 }
614
615
616
617 static void nmdm_drvinit (void *unused);
618
619 static void
620 nmdm_drvinit(void *unused)
621 {
622         nmdminit(0);
623 }
624
625 SYSINIT(nmdmdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, nmdm_drvinit,
626     NULL);