xref: /freebsd/sys/dev/nmdm/nmdm.c (revision 737a12862221332fb7c07e4c139cf39b1cd1afed)
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