nmdm.c revision 73166
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
3385052Sru * $FreeBSD: head/sys/dev/nmdm/nmdm.c 73166 2001-02-27 17:52:49Z julian $
3450477Speter */
351541Srgrimes
361541Srgrimes/*
372168Spaul * Pseudo-nulmodem Driver
382168Spaul */
392168Spaul#include "opt_compat.h"
401541Srgrimes#include <sys/param.h>
411541Srgrimes#include <sys/systm.h>
428876Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
431541Srgrimes#include <sys/ioctl_compat.h>
441541Srgrimes#endif
451541Srgrimes#include <sys/proc.h>
461541Srgrimes#include <sys/tty.h>
471541Srgrimes#include <sys/conf.h>
481541Srgrimes#include <sys/fcntl.h>
491541Srgrimes#include <sys/poll.h>
501541Srgrimes#include <sys/kernel.h>
511541Srgrimes#include <sys/vnode.h>
521541Srgrimes#include <sys/signalvar.h>
531541Srgrimes#include <sys/malloc.h>
541541Srgrimes
551541SrgrimesMALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures");
561541Srgrimes
571541Srgrimesstatic void nmdmstart __P((struct tty *tp));
581541Srgrimesstatic void nmdmstop __P((struct tty *tp, int rw));
591541Srgrimesstatic void wakeup_other __P((struct tty *tp, int flag));
601541Srgrimesstatic void nmdminit __P((int n));
611541Srgrimes
621541Srgrimesstatic	d_open_t	nmdmopen;
631541Srgrimesstatic	d_close_t	nmdmclose;
641541Srgrimesstatic	d_read_t	nmdmread;
651541Srgrimesstatic	d_write_t	nmdmwrite;
6613765Smppstatic	d_ioctl_t	nmdmioctl;
6713765Smpp
681541Srgrimes#define	CDEV_MAJOR	18
691541Srgrimesstatic struct cdevsw nmdm_cdevsw = {
701541Srgrimes	/* open */	nmdmopen,
711541Srgrimes	/* close */	nmdmclose,
725791Swollman	/* read */	nmdmread,
731541Srgrimes	/* write */	nmdmwrite,
741541Srgrimes	/* ioctl */	nmdmioctl,
751541Srgrimes	/* poll */	ttypoll,
761541Srgrimes	/* mmap */	nommap,
771541Srgrimes	/* strategy */	nostrategy,
781541Srgrimes	/* name */	"pts",
791541Srgrimes	/* maj */	CDEV_MAJOR,
801541Srgrimes	/* dump */	nodump,
811541Srgrimes	/* psize */	nopsize,
821541Srgrimes	/* flags */	D_TTY,
831541Srgrimes	/* bmaj */	-1
845833Sbde};
855833Sbde
865833Sbde#define BUFSIZ 100		/* Chunk size iomoved to/from user */
875833Sbde
885833Sbdestruct softpart {
891541Srgrimes	struct tty nm_tty;
901541Srgrimes	dev_t	dev;
911541Srgrimes	int	modemsignals;	/* bits defined in sys/ttycom.h */
921541Srgrimes	int	gotbreak;
931541Srgrimes};
941541Srgrimes
951541Srgrimesstruct	nm_softc {
961541Srgrimes	int	pt_flags;
971541Srgrimes	struct softpart part1, part2;
981541Srgrimes	struct	prison *pt_prison;
991541Srgrimes};
1001541Srgrimes
1011541Srgrimes#define	PF_STOPPED	0x10		/* user told stopped */
1021541Srgrimes
1031541Srgrimesstatic void
10448381Smsmithnmdm_crossover(struct nm_softc *pti,
1057197Swollman		struct softpart *ourpart,
1061541Srgrimes		struct softpart *otherpart);
1071541Srgrimes
1081541Srgrimes#define GETPARTS(tp, ourpart, otherpart) \
1091541Srgrimesdo {	\
1101541Srgrimes	struct nm_softc *pti = tp->t_dev->si_drv1; \
1111541Srgrimes	if (tp == &pti->part1.nm_tty) { \
11293084Sbde		ourpart = &pti->part1; \
11393084Sbde		otherpart = &pti->part2; \
1145791Swollman	} else { \
1155791Swollman		ourpart = &pti->part2; \
116120727Ssam		otherpart = &pti->part1; \
117120727Ssam	}  \
118120727Ssam} while (0)
119120727Ssam
1201541Srgrimes/*
1211541Srgrimes * This function creates and initializes a pair of ttys.
1221541Srgrimes */
1231541Srgrimesstatic void
1241541Srgrimesnmdminit(n)
1251541Srgrimes	int n;
1261541Srgrimes{
1271541Srgrimes	dev_t dev1, dev2;
1281541Srgrimes	struct nm_softc *pt;
1291541Srgrimes
1301541Srgrimes	/* For now we only map the lower 8 bits of the minor */
1311541Srgrimes	if (n & ~0xff)
1321541Srgrimes		return;
1331541Srgrimes
1341541Srgrimes	pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK);
1351541Srgrimes	bzero(pt, sizeof(*pt));
1364104Swollman	pt->part1.dev = dev1 = make_dev(&nmdm_cdevsw, n+n,
1374104Swollman	    0, 0, 0666, "nmdm%dA", n);
1381541Srgrimes	pt->part2.dev = dev2 = make_dev(&nmdm_cdevsw, n+n+1,
1391541Srgrimes	    0, 0, 0666, "nmdm%dB", n);
1401541Srgrimes
1411541Srgrimes	dev1->si_drv1 = dev2->si_drv1 = pt;
1421541Srgrimes	dev1->si_tty = &pt->part1.nm_tty;
1431541Srgrimes	dev2->si_tty = &pt->part2.nm_tty;
1441541Srgrimes	ttyregister(&pt->part1.nm_tty);
14586764Sjlemon	ttyregister(&pt->part2.nm_tty);
1461541Srgrimes	pt->part1.nm_tty.t_oproc = nmdmstart;
1471541Srgrimes	pt->part2.nm_tty.t_oproc = nmdmstart;
14817835Sjulian	pt->part1.nm_tty.t_stop = nmdmstop;
1491541Srgrimes	pt->part2.nm_tty.t_dev = dev1;
1501541Srgrimes	pt->part1.nm_tty.t_dev = dev2;
1511541Srgrimes	pt->part2.nm_tty.t_stop = nmdmstop;
1521541Srgrimes}
1531541Srgrimes
154122921Sandre/*ARGSUSED*/
155122921Sandrestatic	int
156122921Sandrenmdmopen(dev, flag, devtype, p)
157122921Sandre	dev_t dev;
158122921Sandre	int flag, devtype;
1595099Swollman	struct proc *p;
1605099Swollman{
16118839Swollman	register struct tty *tp, *tp2;
1626245Swollman	int error;
16315652Swollman	int minr;
16415652Swollman	dev_t nextdev;
16515652Swollman	struct nm_softc *pti;
16615652Swollman	int is_b;
1671541Srgrimes	int	pair;
1681541Srgrimes	struct	softpart *ourpart, *otherpart;
1691541Srgrimes
1701541Srgrimes	/*
1711541Srgrimes	 * XXX: Gross hack for DEVFS:
1721541Srgrimes	 * If we openned this device, ensure we have the
1731541Srgrimes	 * next one too, so people can open it.
1741541Srgrimes	 */
1751541Srgrimes	minr = dev2unit(dev);
1761541Srgrimes	pair = minr >> 1;
1771541Srgrimes	is_b = minr & 1;
1781541Srgrimes
1791541Srgrimes	if (pair < 127) {
1801541Srgrimes		nextdev = makedev(major(dev), (pair+pair) + 1);
1811541Srgrimes		if (!nextdev->si_drv1) {
1821541Srgrimes			nmdminit(pair + 1);
1831541Srgrimes		}
1841541Srgrimes	}
1851541Srgrimes	if (!dev->si_drv1)
1861541Srgrimes		nmdminit(pair);
1871541Srgrimes
1881541Srgrimes	if (!dev->si_drv1)
1891541Srgrimes		return(ENXIO);
1901541Srgrimes
1911541Srgrimes	pti = dev->si_drv1;
1921541Srgrimes	if (is_b)
1931541Srgrimes		tp = &pti->part2.nm_tty;
1941541Srgrimes	else
1951541Srgrimes		tp = &pti->part1.nm_tty;
1965791Swollman	GETPARTS(tp, ourpart, otherpart);
1971541Srgrimes	tp2 = &otherpart->nm_tty;
19851252Sru	ourpart->modemsignals |= TIOCM_LE;
19951252Sru
20051252Sru	if ((tp->t_state & TS_ISOPEN) == 0) {
2011541Srgrimes		ttychars(tp);		/* Set up default chars */
2021541Srgrimes		tp->t_iflag = TTYDEF_IFLAG;
2031541Srgrimes		tp->t_oflag = TTYDEF_OFLAG;
2041541Srgrimes		tp->t_lflag = TTYDEF_LFLAG;
2051541Srgrimes		tp->t_cflag = TTYDEF_CFLAG;
2061541Srgrimes		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
2071541Srgrimes	} else if (tp->t_state & TS_XCLUDE && suser(p)) {
2081541Srgrimes		return (EBUSY);
2091541Srgrimes	} else if (pti->pt_prison != p->p_ucred->cr_prison) {
2101541Srgrimes		return (EBUSY);
2111541Srgrimes	}
2121541Srgrimes
2131541Srgrimes	/*
2141541Srgrimes	 * If the other side is open we have carrier
21521666Swollman	 */
21621666Swollman	if (tp2->t_state & TS_ISOPEN) {
21789498Sru		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
2181541Srgrimes	}
21951252Sru
22051252Sru	/*
22151252Sru	 * And the other side gets carrier as we are now open.
2221541Srgrimes	 */
2231541Srgrimes	(void)(*linesw[tp2->t_line].l_modem)(tp2, 1);
22451252Sru
2251541Srgrimes	/* External processing makes no sense here */
2261541Srgrimes	tp->t_lflag &= ~EXTPROC;
2271541Srgrimes
2281541Srgrimes	/*
2291541Srgrimes	 * Wait here if we don't have carrier.
2301541Srgrimes	 */
2311541Srgrimes#if 0
23251252Sru	while ((tp->t_state & TS_CARR_ON) == 0) {
2331541Srgrimes		if (flag & FNONBLOCK)
2341541Srgrimes			break;
2351541Srgrimes		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
2361541Srgrimes				 "nmdopn", 0);
2371541Srgrimes		if (error)
2381541Srgrimes			return (error);
2391541Srgrimes	}
2401541Srgrimes#endif
2411541Srgrimes
2421541Srgrimes	/*
2431541Srgrimes	 * Give the line disciplin a chance to set this end up.
2441541Srgrimes	 */
2451541Srgrimes	error = (*linesw[tp->t_line].l_open)(dev, tp);
2461541Srgrimes
2471541Srgrimes	/*
2481541Srgrimes	 * Wake up the other side.
2491541Srgrimes	 * Theoretically not needed.
2501541Srgrimes	 */
2511541Srgrimes	ourpart->modemsignals |= TIOCM_DTR;
2521541Srgrimes	nmdm_crossover(pti, ourpart, otherpart);
2531541Srgrimes	if (error == 0)
2541541Srgrimes		wakeup_other(tp, FREAD|FWRITE); /* XXX */
2551541Srgrimes	return (error);
2561541Srgrimes}
2571541Srgrimes
2581541Srgrimesstatic	int
25985074Srunmdmclose(dev, flag, mode, p)
26085074Sru	dev_t dev;
26185074Sru	int flag, mode;
2621541Srgrimes	struct proc *p;
2631541Srgrimes{
26455205Speter	register struct tty *tp, *tp2;
265117752Shsu	int err;
266120727Ssam	struct softpart *ourpart, *otherpart;
267120727Ssam
268120727Ssam	/*
269120727Ssam	 * let the other end know that the game is up
270120727Ssam	 */
271120727Ssam	tp = dev->si_tty;
272117752Shsu	GETPARTS(tp, ourpart, otherpart);
273122334Ssam	tp2 = &otherpart->nm_tty;
274122334Ssam	(void)(*linesw[tp2->t_line].l_modem)(tp2, 0);
275122334Ssam
276122334Ssam	/*
277122334Ssam	 * XXX MDMBUF makes no sense for nmdms but would inhibit the above
278122334Ssam	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
279122334Ssam	 * l_modem()s that ignore carrier drop make no sense for nmdms but
280122334Ssam	 * may be in use because other parts of the line discipline make
281122334Ssam	 * sense for nmdms.  Recover by doing everything that a normal
282122334Ssam	 * ttymodem() would have done except for sending a SIGHUP.
283122334Ssam	 */
284122334Ssam	if (tp2->t_state & TS_ISOPEN) {
285122334Ssam		tp2->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
286122334Ssam		tp2->t_state |= TS_ZOMBIE;
287122334Ssam		ttyflush(tp2, FREAD | FWRITE);
288122334Ssam	}
289122334Ssam
290122334Ssam	err = (*linesw[tp->t_line].l_close)(tp, flag);
291122334Ssam	ourpart->modemsignals &= ~TIOCM_DTR;
292122334Ssam	nmdm_crossover(dev->si_drv1, ourpart, otherpart);
293122334Ssam	nmdmstop(tp, FREAD|FWRITE);
294122334Ssam	(void) ttyclose(tp);
29546568Speter	return (err);
296122334Ssam}
297122334Ssam
298122334Ssamstatic	int
299120727Ssamnmdmread(dev, uio, flag)
3001541Srgrimes	dev_t dev;
3019759Sbde	struct uio *uio;
3021541Srgrimes	int flag;
30321666Swollman{
30421666Swollman	int error = 0;
30592725Salfred	struct tty *tp, *tp2;
30692725Salfred	struct softpart *ourpart, *otherpart;
30792725Salfred
30892725Salfred	tp = dev->si_tty;
30992725Salfred	GETPARTS(tp, ourpart, otherpart);
31092725Salfred	tp2 = &otherpart->nm_tty;
31192725Salfred
312120727Ssam#if 0
31392725Salfred	if (tp2->t_state & TS_ISOPEN) {
31492725Salfred		error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
315120727Ssam		wakeup_other(tp, FWRITE);
316120727Ssam	} else {
317121770Ssam		if (flag & IO_NDELAY) {
31892725Salfred			return (EWOULDBLOCK);
31992725Salfred		}
32092725Salfred		error = tsleep(TSA_PTC_READ(tp),
32192725Salfred				TTIPRI | PCATCH, "nmdout", 0);
322120727Ssam		}
32392725Salfred	}
32492725Salfred#else
32592725Salfred	if ((error = (*linesw[tp->t_line].l_read)(tp, uio, flag)) == 0)
326111767Smdodd		wakeup_other(tp, FWRITE);
3271541Srgrimes#endif
3282168Spaul	return (error);
3292168Spaul}
330
331/*
332 * Write to pseudo-tty.
333 * Wakeups of controlling tty will happen
334 * indirectly, when tty driver calls nmdmstart.
335 */
336static	int
337nmdmwrite(dev, uio, flag)
338	dev_t dev;
339	struct uio *uio;
340	int flag;
341{
342	register u_char *cp = 0;
343	register int cc = 0;
344	u_char locbuf[BUFSIZ];
345	int cnt = 0;
346	int error = 0;
347	struct tty *tp1, *tp;
348	struct softpart *ourpart, *otherpart;
349
350	tp1 = dev->si_tty;
351	/*
352	 * Get the other tty struct.
353	 * basically we are writing into the INPUT side of the other device.
354	 */
355	GETPARTS(tp1, ourpart, otherpart);
356	tp = &otherpart->nm_tty;
357
358again:
359	if ((tp->t_state & TS_ISOPEN) == 0)
360		return (EIO);
361	while (uio->uio_resid > 0 || cc > 0) {
362		/*
363		 * Fill up the buffer if it's empty
364		 */
365		if (cc == 0) {
366			cc = min(uio->uio_resid, BUFSIZ);
367			cp = locbuf;
368			error = uiomove((caddr_t)cp, cc, uio);
369			if (error)
370				return (error);
371			/* check again for safety */
372			if ((tp->t_state & TS_ISOPEN) == 0) {
373				/* adjust for data copied in but not written */
374				uio->uio_resid += cc;
375				return (EIO);
376			}
377		}
378		while (cc > 0) {
379			if (((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= (TTYHOG-2))
380			&& ((tp->t_canq.c_cc > 0) || !(tp->t_iflag&ICANON))) {
381				/*
382	 			 * Come here to wait for space in outq,
383				 * or space in rawq, or an empty canq.
384	 			 */
385				wakeup(TSA_HUP_OR_INPUT(tp));
386				if ((tp->t_state & TS_CONNECTED) == 0) {
387					/*
388					 * Data piled up because not connected.
389					 * Adjust for data copied in but
390					 * not written.
391					 */
392					uio->uio_resid += cc;
393					return (EIO);
394				}
395				if (flag & IO_NDELAY) {
396					/*
397				         * Don't wait if asked not to.
398					 * Adjust for data copied in but
399					 * not written.
400					 */
401					uio->uio_resid += cc;
402					if (cnt == 0)
403						return (EWOULDBLOCK);
404					return (0);
405				}
406				error = tsleep(TSA_PTC_WRITE(tp),
407						TTOPRI | PCATCH, "nmdout", 0);
408				if (error) {
409					/*
410					 * Tsleep returned (signal?).
411					 * Go find out what the user wants.
412					 * adjust for data copied in but
413					 * not written
414					 */
415					uio->uio_resid += cc;
416					return (error);
417				}
418				goto again;
419			}
420			(*linesw[tp->t_line].l_rint)(*cp++, tp);
421			cnt++;
422			cc--;
423		}
424		cc = 0;
425	}
426	return (0);
427}
428
429/*
430 * Start output on pseudo-tty.
431 * Wake up process selecting or sleeping for input from controlling tty.
432 */
433static void
434nmdmstart(tp)
435	struct tty *tp;
436{
437	register struct nm_softc *pti = tp->t_dev->si_drv1;
438
439	if (tp->t_state & TS_TTSTOP)
440		return;
441	pti->pt_flags &= ~PF_STOPPED;
442	wakeup_other(tp, FREAD);
443}
444
445/* Wakes up the OTHER tty;*/
446static void
447wakeup_other(tp, flag)
448	struct tty *tp;
449	int flag;
450{
451	struct softpart *ourpart, *otherpart;
452
453	GETPARTS(tp, ourpart, otherpart);
454	if (flag & FREAD) {
455		selwakeup(&otherpart->nm_tty.t_rsel);
456		wakeup(TSA_PTC_READ((&otherpart->nm_tty)));
457	}
458	if (flag & FWRITE) {
459		selwakeup(&otherpart->nm_tty.t_wsel);
460		wakeup(TSA_PTC_WRITE((&otherpart->nm_tty)));
461	}
462}
463
464static	void
465nmdmstop(tp, flush)
466	register struct tty *tp;
467	int flush;
468{
469	struct nm_softc *pti = tp->t_dev->si_drv1;
470	int flag;
471
472	/* note: FLUSHREAD and FLUSHWRITE already ok */
473	if (flush == 0) {
474		flush = TIOCPKT_STOP;
475		pti->pt_flags |= PF_STOPPED;
476	} else
477		pti->pt_flags &= ~PF_STOPPED;
478	/* change of perspective */
479	flag = 0;
480	if (flush & FREAD)
481		flag |= FWRITE;
482	if (flush & FWRITE)
483		flag |= FREAD;
484	wakeup_other(tp, flag);
485}
486
487#if 0
488static int
489nmdmpoll(dev_t dev, int events, struct proc *p)
490{
491	register struct tty *tp = dev->si_tty;
492	register struct tty *tp2;
493	int revents = 0;
494	int s;
495	struct softpart *ourpart, *otherpart;
496
497	GETPARTS(tp, ourpart, otherpart);
498	tp2 = &otherpart->nm_tty;
499
500	if ((tp->t_state & TS_CONNECTED) == 0)
501		return (seltrue(dev, events, p) | POLLHUP);
502
503	/*
504	 * Need to block timeouts (ttrstart).
505	 */
506	s = spltty();
507
508	/*
509	 * First check if there is something to report immediatly.
510	 */
511	if ((events & (POLLIN | POLLRDNORM))) {
512		if (tp->t_iflag & ICANON)  {
513			if (tp->t_canq.c_cc)
514				revents |= events & (POLLIN | POLLRDNORM);
515		} else {
516			if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
517				revents |= events & (POLLIN | POLLRDNORM);
518		}
519	}
520
521	/*
522	 * check if there is room in the other tty's input buffers.
523	 */
524	if ((events & (POLLOUT | POLLWRNORM))
525	&& ((tp2->t_rawq.c_cc + tp2->t_canq.c_cc < TTYHOG - 2)
526	   || (tp2->t_canq.c_cc == 0 && (tp2->t_iflag & ICANON)))) {
527			revents |= events & (POLLOUT | POLLWRNORM);
528	}
529
530	if (events & POLLHUP)
531		if ((tp->t_state & TS_CARR_ON) == 0)
532			revents |= POLLHUP;
533
534	/*
535	 * If nothing immediate, set us to return when something IS found.
536	 */
537	if (revents == 0) {
538		if (events & (POLLIN | POLLRDNORM))
539			selrecord(p, &tp->t_rsel);
540
541		if (events & (POLLOUT | POLLWRNORM))
542			selrecord(p, &tp->t_wsel);
543	}
544	splx(s);
545
546	return (revents);
547}
548#endif	/* 0 */
549
550/*ARGSUSED*/
551static	int
552nmdmioctl(dev, cmd, data, flag, p)
553	dev_t dev;
554	u_long cmd;
555	caddr_t data;
556	int flag;
557	struct proc *p;
558{
559	register struct tty *tp = dev->si_tty;
560	struct nm_softc *pti = dev->si_drv1;
561	int error, s;
562	register struct tty *tp2;
563	struct softpart *ourpart, *otherpart;
564
565	s = spltty();
566	GETPARTS(tp, ourpart, otherpart);
567	tp2 = &otherpart->nm_tty;
568
569	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
570	if (error == ENOIOCTL)
571		 error = ttioctl(tp, cmd, data, flag);
572	if (error == ENOIOCTL) {
573		switch (cmd) {
574		case TIOCSBRK:
575			otherpart->gotbreak = 1;
576			break;
577		case TIOCCBRK:
578			break;
579		case TIOCSDTR:
580			ourpart->modemsignals |= TIOCM_DTR;
581			break;
582		case TIOCCDTR:
583			ourpart->modemsignals &= TIOCM_DTR;
584			break;
585		case TIOCMSET:
586			ourpart->modemsignals = *(int *)data;
587			otherpart->modemsignals = *(int *)data;
588			break;
589		case TIOCMBIS:
590			ourpart->modemsignals |= *(int *)data;
591			break;
592		case TIOCMBIC:
593			ourpart->modemsignals &= ~(*(int *)data);
594			otherpart->modemsignals &= ~(*(int *)data);
595			break;
596		case TIOCMGET:
597			*(int *)data = ourpart->modemsignals;
598			break;
599		case TIOCMSDTRWAIT:
600			break;
601		case TIOCMGDTRWAIT:
602			*(int *)data = 0;
603			break;
604		case TIOCTIMESTAMP:
605		case TIOCDCDTIMESTAMP:
606		default:
607			splx(s);
608			error = ENOTTY;
609			return (error);
610		}
611		error = 0;
612		nmdm_crossover(pti, ourpart, otherpart);
613	}
614	splx(s);
615	return (error);
616}
617
618static void
619nmdm_crossover(struct nm_softc *pti,
620		struct softpart *ourpart,
621		struct softpart *otherpart)
622{
623	otherpart->modemsignals &= ~(TIOCM_CTS|TIOCM_CAR);
624	if (ourpart->modemsignals & TIOCM_RTS)
625		otherpart->modemsignals |= TIOCM_CTS;
626	if (ourpart->modemsignals & TIOCM_DTR)
627		otherpart->modemsignals |= TIOCM_CAR;
628}
629
630
631
632static void nmdm_drvinit __P((void *unused));
633
634static void
635nmdm_drvinit(unused)
636	void *unused;
637{
638	cdevsw_add(&nmdm_cdevsw);
639	/* XXX: Gross hack for DEVFS */
640	nmdminit(0);
641}
642
643SYSINIT(nmdmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,nmdm_drvinit,NULL)
644