[net.sources] Dialing In/Out through same port

bentson (04/14/83)

Here's yet another way to use a line for both dial-in and dial-out.
I got the idea for this from Donn Terry (csu-cs!hp-dcd!donn) who
thinks he spotted something about this on the net.  (If anyone can
help with proper attribution of this idea, please respond by mail.)
Although this discussion relates specifically to 4.1bsd, other Un*x
should be able to fiddle this a bit to get the same results.

Randy Bentson
Colo State U - Comp Sci
Ft. Collins, CO
303/491-7016
{hplabs,lanl-a,lll-crg,hao,cires}!csu-cs!bentson

GENERAL CONCEPT
There are first class and second class citizens in the world of tty's.
The first class citizens have the OUTLINE bit set in the minor device
number.  Having the outline bit set is used for dial-in/dial-out
lines.  What happens is that a process such as init or getty can hang
an open on a second-class line and wait for carrier detect.  If a dial-
out process does an open on a first-class line, the second class line
will not open even if carrier detect does come true for the process
using the first class line until that "first class process" closes it.
Processes using a first class line can do several opens on those lines
if they wish.

/DEV ENTRIES
This is an excerpt of our /dev directory listing. Port tty06 is the real
dialer port. The ports cua0-3 are multiplex files used by the dnd daemon
which actually does the dialing on the real dialer port.

crw------- 1 root      1,  6 Mar 15 13:04 /dev/tty06
mrw-rw-rw- 1 root      9,  8 Mar 15 11:01 /dev/cua0
mrw-rw-rw- 1 root      9,  7 Mar 15 13:04 /dev/cua1
mrw-rw-rw- 1 root      9,  6 Mar 15 11:01 /dev/cua2
mrw-rw-rw- 1 root      9,  5 Mar 15 11:01 /dev/cua3

Tty05 is the second class version of the first class port cul0. That
is, both open the same line, but one has priority over the other.

crw--w--w- 1 root      1,  5 Mar 14 18:46 /dev/tty05
crw-rw-rw- 1 root      1,133 Mar 15 13:08 /dev/cul0

This is the second dial-in/dial-out port on our system.  There is no
apparent limit to the number of such dual ports beyond the maximum
second class minor device number limit of 128.

crw--w--w- 1 root      1,  4 Mar 15 12:50 /dev/tty04
crw------- 1 root      1,132 Mar 12 15:25 /dev/cul1

TTY.H FILE
Make one change to /sys/h/tty.h so that the line state can remember
that there is a request for the line as a first class citizen. It
doesn't appear that NDQB is used anywhere in the system so I preempted
use of the bit.

/* 06Mar83 RABentson changed following line from
	#define	NDQB	010000
   to the following to support first/second class open
*/
#define OUTFLAG 010000		/* first class open in progress */

DZ DRIVER
I've used diff with two lines of context.  Then here's the changes in
the dz driver. Notice that I've changed the location of the splN()
calls. I believe that this is a more stable use of the calls.

*** /sys/dev/dz.c	Tue Apr  5 16:41:06 1983
--- /sys/dev/dz.7Oct81.c	Wed Oct  7 14:46:11 1981
***************
*** 1,4
- /* 31Mar83 RABentson put delay in close so line stays on-hook for a bit */
- /* 06Mar83 RABentson added support for "first/second class open" */
  /*	dz.c	4.29	81/07/25	*/
  

--- 1,2 -----
  /*	dz.c	4.29	81/07/25	*/
  
***************
*** 30,34
   * Driver information for auto-configuration stuff.
   */
- extern	lbolt;		/* 31Mar83 */
  int	dzprobe(), dzattach(), dzrint();
  struct	uba_device *dzinfo[NDZ];

--- 28,31 -----
   * Driver information for auto-configuration stuff.
   */
  int	dzprobe(), dzattach(), dzrint();
  struct	uba_device *dzinfo[NDZ];
***************
*** 66,72
  #define	DZ_ON	1
  #define	DZ_OFF	0
- 
- /* Flag indicating first class line */ /*06Mar83*/
- #define OUTLINE 0200 /*06Mar83*/
   
  int	dzstart(), dzxint(), dzdma();

--- 63,66 -----
  #define	DZ_ON	1
  #define	DZ_OFF	0
   
  int	dzstart(), dzxint(), dzdma();
***************
*** 152,156
  	register int unit;
   
! 	unit = minor(dev & ~OUTLINE); /*06Mar83*/
  	if (unit >= dz_cnt || dzpdma[unit].p_addr == 0) {
  		u.u_error = ENXIO;

--- 146,150 -----
  	register int unit;
   
! 	unit = minor(dev);
  	if (unit >= dz_cnt || dzpdma[unit].p_addr == 0) {
  		u.u_error = ENXIO;
***************
*** 161,166
  	tp->t_oproc = dzstart;
  	tp->t_iproc = NULL;
- 	(void) spl5();
- again: /*06Mar83*/
  	tp->t_state |= WOPEN;
  	if ((tp->t_state & ISOPEN) == 0) {

--- 155,158 -----
  	tp->t_oproc = dzstart;
  	tp->t_iproc = NULL;
  	tp->t_state |= WOPEN;
  	if ((tp->t_state & ISOPEN) == 0) {
***************
*** 172,176
  	} else if (tp->t_state&XCLUDE && u.u_uid != 0) {
  		u.u_error = EBUSY;
- 		(void) spl0();
  		return;
  	} else if ((dev & OUTLINE) && !(tp->t_state & OUTFLAG)) { /*06Mar83*/

--- 164,167 -----
  	} else if (tp->t_state&XCLUDE && u.u_uid != 0) {
  		u.u_error = EBUSY;
  		return;
  	}
***************
*** 174,181
  		(void) spl0();
  		return;
- 	} else if ((dev & OUTLINE) && !(tp->t_state & OUTFLAG)) { /*06Mar83*/
- 		u.u_error = ENXIO; /*06Mar83*/
- 		(void) spl0(); /*06Mar83*/
- 		return; /*06Mar83*/
  	}
  	if (dev & OUTLINE) tp->t_state |= OUTFLAG; /*06Mar83*/

--- 165,168 -----
  		u.u_error = EBUSY;
  		return;
  	}
  	dzmodem(unit, DZ_ON);
***************
*** 179,183
  		return; /*06Mar83*/
  	}
- 	if (dev & OUTLINE) tp->t_state |= OUTFLAG; /*06Mar83*/
  	dzmodem(unit, DZ_ON);
  	if (!(tp->t_state & CARR_ON) ||

--- 166,169 -----
  		return;
  	}
  	dzmodem(unit, DZ_ON);
  	(void) spl5();
***************
*** 181,187
  	if (dev & OUTLINE) tp->t_state |= OUTFLAG; /*06Mar83*/
  	dzmodem(unit, DZ_ON);
! 	if (!(tp->t_state & CARR_ON) ||
! 	    ((tp->t_state & OUTFLAG) && /*06Mar83*/
! 	    !(dev & OUTLINE))) { /*06Mar83*/
  		tp->t_state |= WOPEN;
  		sleep((caddr_t)&tp->t_rawq, TTIPRI);

--- 167,172 -----
  	}
  	dzmodem(unit, DZ_ON);
! 	(void) spl5();
! 	while ((tp->t_state & CARR_ON) == 0) {
  		tp->t_state |= WOPEN;
  		sleep((caddr_t)&tp->t_rawq, TTIPRI);
***************
*** 186,190
  		tp->t_state |= WOPEN;
  		sleep((caddr_t)&tp->t_rawq, TTIPRI);
- 		goto again; /*06Mar83*/
  	}
  	(void) spl0();

--- 171,174 -----
  		tp->t_state |= WOPEN;
  		sleep((caddr_t)&tp->t_rawq, TTIPRI);
  	}
  	(void) spl0();
***************
*** 189,193
  	}
  	(void) spl0();
! 	(*linesw[tp->t_line].l_open)(dev & ~OUTLINE, tp); /*06Mar83*/
  }
   

--- 173,177 -----
  	}
  	(void) spl0();
! 	(*linesw[tp->t_line].l_open)(dev, tp);
  }
   
***************
*** 200,204
  	int dz;
   
! 	unit = minor(dev & ~OUTLINE); /*06Mar83*/
  	dz = unit >> 3;
  	tp = &dz_tty[unit];

--- 184,188 -----
  	int dz;
   
! 	unit = minor(dev);
  	dz = unit >> 3;
  	tp = &dz_tty[unit];
***************
*** 204,208
  	tp = &dz_tty[unit];
  	(*linesw[tp->t_line].l_close)(tp);
- 	tp->t_state &= ~OUTFLAG;
  	((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
  	    (dz_brk[dz] &= ~(1 << (unit&07)));

--- 188,191 -----
  	tp = &dz_tty[unit];
  	(*linesw[tp->t_line].l_close)(tp);
  	((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
  	    (dz_brk[dz] &= ~(1 << (unit&07)));
***************
*** 217,221
  	register struct tty *tp;
   
! 	tp = &dz_tty[minor(dev & ~OUTLINE)]; /*06Mar83*/
  	(*linesw[tp->t_line].l_read)(tp);
  }

--- 200,204 -----
  	register struct tty *tp;
   
! 	tp = &dz_tty[minor(dev)];
  	(*linesw[tp->t_line].l_read)(tp);
  }
***************
*** 226,230
  	register struct tty *tp;
   
! 	tp = &dz_tty[minor(dev & ~OUTLINE)]; /*06Mar83*/
  	(*linesw[tp->t_line].l_write)(tp);
  }

--- 209,213 -----
  	register struct tty *tp;
   
! 	tp = &dz_tty[minor(dev)];
  	(*linesw[tp->t_line].l_write)(tp);
  }
***************
*** 283,287
  {
  	register struct tty *tp;
! 	register int unit = minor(dev & ~OUTLINE); /*06Mar83*/
  	register int dz = unit >> 3;
   

--- 266,270 -----
  {
  	register struct tty *tp;
! 	register int unit = minor(dev);
  	register int dz = unit >> 3;
   
***************
*** 432,436
  	dzaddr = dzpdma[unit].p_addr;
  	bit = 1<<(unit&07);
! 	if (flag == DZ_OFF){
  		dzaddr->dzdtr &= ~bit;
  		/* 31Mar83 Pause at least three seconds before allowing DTR to

--- 415,419 -----
  	dzaddr = dzpdma[unit].p_addr;
  	bit = 1<<(unit&07);
! 	if (flag == DZ_OFF)
  		dzaddr->dzdtr &= ~bit;
  	else
***************
*** 434,444
  	if (flag == DZ_OFF){
  		dzaddr->dzdtr &= ~bit;
! 		/* 31Mar83 Pause a long time before allowing DTR to be
!                *  turned back on. This will ensure the line is hung-up.
!                */
! 		sleep((caddr_t)&lbolt, TTIPRI);
! 		sleep((caddr_t)&lbolt, TTIPRI);
! 		sleep((caddr_t)&lbolt, TTIPRI);
! 		sleep((caddr_t)&lbolt, TTIPRI);
! 		sleep((caddr_t)&lbolt, TTIPRI);
! 		sleep((caddr_t)&lbolt, TTIPRI);
! 		sleep((caddr_t)&lbolt, TTIPRI);
! 	}else
  		dzaddr->dzdtr |= bit;
  }

--- 417,421 -----
  	if (flag == DZ_OFF)
  		dzaddr->dzdtr &= ~bit;
! 	else
  		dzaddr->dzdtr |= bit;
  }