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; }