[comp.dcom.modems] dial in / out on same line

chris@mimsy.UUCP (Chris Torek) (01/25/88)

I have written about this before, but let me try for concise.  The
trick is to have two flags per line.  One says `pretend carrier is
present'; the other says `this line is being used by a dialout
program'.  In my current implementation, the former is done with
the TS_CARR_ON flag, and the latter with an XX_inout[] array (where
XX is the device; see below).

In the device driver, opening the `normal' line works like this:

	for (;;) {
		if (dialout is not in use) {
			assert ready;	/* let the modem answer the phone */
			if (there is a carrier)
				break;
		}
		wait;
	}
	open the line;

The dialout code looks like this:

	if (the line is in use)
		error(busy);
	assert ready, dialout, and software carrier;
	open the line;

The carrier-detect status change code looks like this:

	if (there is a real carrier) {
		if (dialout in use) {
			/*
			 * We must have got through, so let us know when/if
			 * the line drops.
			 *
			deassert software carrier;
			 *
			 * The software carrier is `deasserted' by doing
			 * nothing.  When the carrier status changes
			 * again it will be to `there is no real carrier'
			 * and we will do the `else' below.
			 */
		}
	} else {
		hang up the line as usual;
	}

and the close code says

	if (this is the dialout line || hangup-on-close set) {
		drop the line, pausing long enough for
			the modem to see it;
	}
	do close protocol;
	if (this is the dialout line) {
		deassert dialout;
		reset software carrier from saved original state;
		wake up anyone waiting for dialin use;
			/* this last so it can reassert ready */
	}

In practise, this is implemented as follows, using the DMF driver
as an example:

dmfopen:
	if ((tp->t_state & TS_ISOPEN) == 0) {
		... set initial state ...
	} else if ((tp->t_state & TS_XCLUDE || dial) && u.u_uid != 0)
		return (EBUSY);
	bit = 1 << (unit & 7);
	s = spltty();
	if (dial)
		dmf_inout[dmf] |= bit;
	/* this is an Ultrix compatibility hack.  FNDELAY is set if dial */
	if (flags & FNDELAY) {
		(void) dmfmctl(dev, DMF_ON, DMSET);
		tp->t_state |= TS_CARR_ON;
	} else {
		for (;;) {
			if ((dmf_inout[dmf] & bit) == 0 &&
			    (dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8) ||
			     dmfsoftCAR[dmf] & bit))
				break;
			tp->t_state |= TS_WOPEN;
			sleep((caddr_t)&tp->t_state, TTIPRI);
				/* stock drivers use &tp->t_rawq; beware */
		}
		tp->t_state |= TS_CARR_ON;
	}
	splx(s);
	return ((*linesw[tp->t_line].l_open)(dev, tp));

dmfclose:
	(*linesw[tp->t_line].l_close)(tp);
	(void) dmfmctl(unit, DMF_BRK, DMBIC);
	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0 || dial) {
		(void) dmfmctl(unit, DMF_OFF, DMSET);
		timeout(wakeup, (caddr_t)&tp->t_flags, hz);
		sleep((caddr_t)&tp->t_flags, PZERO - 1);
	}
	ttyclose(tp);
	if (dial) {
		dmf_inout[unit >> 3] &= ~(1 << (unit & 7));
		wakeup((caddr_t)&tp->t_state);
			/* again, 4.3 drivers use &tp->t_rawq */
	}
	return (0);

dmfrint, if carrier status changes:

		if (addr->dmfrms & DMF_CAR)	/* have carrier */
			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
		else if ((dmfsoftCAR[dmf] & (1 << unit)) == 0 &&
		    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
			... drop the line ...

How `dial' is determined is up to the driver.  I used separate
major device numbers, fearing to run out of minor devices if I took
a bit (particularly in the case of the 4.3BSD dmf driver, which
already uses bit 7 to identify the printer port).  Since we are
now converting to Annex terminal servers, I would probably use
a bit now.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

casey@lll-crg.llnl.gov (Casey Leedom) (01/26/88)

In article <10330@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>I have written about this before, but let me try for concise[ness]. ...

  The problem with the omitted description is that it's just too
complex.  There's already a perfectly reasonable way of doing what's
necessary and it just isn't being used.  The current mechanism used by
the 4.3BSD drivers to do soft carrier is really for the birds.

  All that really needs to be done [for 4.3BSD] is to declare the flags
parameters in the various driver routines (openi in sys_inode.c calls all
the drivers with the flags word passed in to the original open, but none
of the 4.3BSD tty drivers declares that parameter), and use O_NDELAY to
indicate one doesn't want to wait for carrier instead of the stupid soft
carrier flag arrays currently in use.  The only changes necessary at the
application level would be to have getty, tip, uucp, etc. all open with
O_EXCL and have tip, uucp, etc. also use O_NDELAY.

  These fixes are trivial, straight forward, easy to understand and use,
and are in the original spirit of the open flags parameter.  Anything
else that plays around with the open code is a kludge.  The only other
idea I've heard of any merit is to have a modem server/daemon that can be
contacted for a modem, but that requires the writing of a whole new
program, the design of new paradigms, and probably a significant rewrite
of the application programs needing access to modems.

  Note that the above descriptions all refer explicitly to 4.3BSD but the
concepts should be portable to SYSV.

Casey

casey@lll-crg.llnl.gov (Casey Leedom) (01/28/88)

In article <10354@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
> Nonetheless, I believe two devices is most appropriate.  After all,
> the modem is, virtually speaking, two devices!

  After listening to your and Carl Gutekunst's (csg@pryamid.UUCP)
arguments I'm going to agree with you.  I do think that 4BSD should
support O_NDELAY on tty lines if for no other reasons than it's intuitive
and is apparently compatible with SYSV.  But fundamentally you're right,
we're talking about two different pseudo devices which are implemented on
the same physical device.  Sorry for the stones.

Casey

rpw3@amdcad.AMD.COM (Rob Warnock) (01/28/88)

Just another voice supporting the "two devices" view. I also am/was a
user/designer of the Fortune box, like Dave Yost, and I have to say the
"minor+128" dialout hack works VERY cleanly. NO changes to getty/cu/uucp,
etc. Getty hangs on /dev/ttyd* and uucp/cu talks to /dev/cul*. No need for
any *_EXCL stuff, since the two minor devices (x and x+128) are exclusive
against each other you don't need to make either exclusive against itself.
(E.g., can do "stty >/dev/culX" to see what went wrong with a uucp.)


Rob Warnock
Systems Architecture Consultant

UUCP:	  {amdcad,fortune,sun,attmail}!redwood!rpw3
ATTmail:  !rpw3
DDD:	  (415)572-2607
USPS:	  627 26th Ave, San Mateo, CA  94403

wes@obie.UUCP (Barnacle Wes) (02/04/88)

In article <3015@lll-winken.llnl.gov>, casey@lll-crg.llnl.gov (Casey Leedom) writes:
> In article <10354@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
> > Nonetheless, I believe two devices is most appropriate.  After all,
> > the modem is, virtually speaking, two devices!
> 
>                                        ...But fundamentally you're right,
> we're talking about two different pseudo devices which are implemented on
> the same physical device.  Sorry for the stones.

Right.  As a matter of fact, MicroPort supports different 'pseudo
devices' for the tty ports in their '286 and '386 System V: /dev/tty0
also maps to /dev/ttym0 and /dev/ttyM0.  You can run a getty on M0,
and call out on m0.  If anything but getty (i.e. a login process) has
M0 open, the m0 open will fail.  When m0 is opened, the M0 process
just blocks until m0 is closed.  Clever, and works pretty well.

-- 
	{backbones}!utah-cs!utah-gr!uplherc!sp7040!obie!wes

	"Against Stupidity, The Gods Themselves Contend in Vain."
							-- Asimov

steve@nuchat.UUCP (Steve Nuchia) (02/08/88)

This thread seems to be dancing around the tty driver issues
concerning bidirectional use of a line.

This is about the only thing Microport got right from the
beginning, and seeing how well their mechanism (I don't
know where it originated) works I implemented it for my
2.10 BSD client, who is quite pleased also.

You use two different device files for each physical line -
using a bit in the minor device number as a flag differentiating
the incoming and outgoing version.

The open on the incoming (usually getty) blocks waiting for carrier.  
Only one logical device can be open on a line at one time, attempts
to open the outgoing side while the incoming side is open (carrier
high) fail.

One compilcation is that you need to play games with the uucp lock
files to make uucp hunt for an open line properly.

I've got a DHV11 driver for 2.10 (should work in 4.3 too) that
deals with that board's braindamage nicely and implements the
scheme described.  I've also got a getty replacement for microport
that plays the right uucp lockfile games.

The driver requires the proper lisence horse hockey but I can
give the getty away for the asking.

-- 
Steve Nuchia	    | [...] but the machine would probably be allowed no mercy.
uunet!nuchat!steve  | In other words then, if a machine is expected to be
(713) 334 6720	    | infallible, it cannot be intelligent.  - Alan Turing, 1947

sob@academ.UUCP (Stan Barber) (02/11/88)

It should be pointed out that this scheme is much like the SunOS scheme.
It should also be pointed out that it is far superior to acucntrl-type
approaches. Alas, some of use don't have kernel sources.... sigh.



-- 
Stan	     uucp:{killer,rice,hoptoad}!academ!sob     Opinions expressed here
Olan         domain:sob@tmc.edu                            are ONLY mine &
Barber       CIS:71565,623   BBS:(713)790-9004               noone else's.