dave@lsuc.UUCP (David Sherman) (01/30/85)
Scenario: a Perkin-Elmer 3220 running v7, with source. Various lines to modems and similar DCE devices. Normally, init waits on an open(2) call; when a call comes in to the modem, the modem raises CXR (carrier detect), the open succeeds, and init starts up a getty. Fine. Occasionally, I want an open to succeed whether or not CXR is asserted by the modem. For example, I want to call out with cu(1). I am *not* interested in solutions which involve changing a setting on the modem, or jumpers within the cable. This change has to be possible from the software, on any line at any time. Looking at the code in /usr/sys/dev/vdu.c, I find: vduopen(dev) { ... vduenab(tp); ... while (!(tp->t_state&CARR_ON)) sleep(&tp->t_rawq, TTIPRI); ... } vduenab(atp) { ... stat = ss(radd); if ((stat&CARR_OFF) == 0) tp->t_state |= CARR_ON; ... } So it looks like the change is fairly simple: given an indication that we don't care about the CARR_OFF (hardware) bit, vduenab can simply turn on the CARR_ON indicator in t_state and we're off to the races. Question (for those who are still with me): how do I get that indication to the kernel - that is, that I want the open to work whether or not the carrier is asserted? I can't use an ioctl, because you have to get the device open first before you can ioctl. Do I have to go through the hassle and overhead of another, almost identical, device driver, which points to the same address? Is there a better way? All ideas greatly appreciated. Dave Sherman The Law Society of Upper Canada Toronto -- {utzoo pesnta nrcaero utcs}!lsuc!dave {allegra decvax ihnp4 linus}!utcsrgv!lsuc!dave
jer@peora.UUCP (J. Eric Roskos) (01/31/85)
> Scenario: a Perkin-Elmer 3220 running v7, with source. Various > lines to modems and similar DCE devices. Normally, init waits on > an open(2) call; when a call comes in to the modem, the modem > raises CXR (carrier detect), the open succeeds, and init starts > up a getty. Fine. > > Occasionally, I want an open to succeed whether or not CXR is > asserted by the modem. For example, I want to call out with cu(1). > I am *not* interested in solutions which involve changing a setting > on the modem, or jumpers within the cable. This change has to > be possible from the software, on any line at any time. Fortunately, I made this change to our system about a month ago, as part of an implementation of a modification to UUCP. The change is a little more complicated than what you've described, although not unduly so. In addition to the problems you listed, if you just allow the open to proceed with no carrier, other parts of the tty driver will throw away characters due to the no-carrier condition. The best way to do this is to define another device which allows opening with no carrier. It doesn't require any duplication of code, and leads to a really straightforward implementation of the original UUCP ACU dialing code (the original UUCP ACU handler works with no modifications), besides. The following diffs show the changes. The files tty.c, vdu.c, and mkconf.c must be changed: tty.c and vdu.c to change logic in the handlers, mkconf.c to add the new device (which comes out as device 25 on the PE Edition VII implementation as distributed, I believe). The changes work as follows. When you open a tty using the new device id, the flag DKCALL is set in the vdu structure to indicate this fact. Then, throughout the driver, this flag is checked (in disjunction with CARR_ON) wherever carrier detection is done. (I used DKCALL simply because it was not used by the vdu driver, and there were no unassigned bits available to use. You might want to rename DKCALL via a #define to improve the readability of the program.) A drawback of this approach (which you must be careful about) is that there are 2 device ids for each device, and the device id used in the LAST SUCCESSFUL open done to the device determines whether carrier is checked for or not. In short, you should have only one of the 2 devices open at any one time. A very strong advantage of this approach is this: you can do an open() call on the original (carrier-detecting) device, which will be suspended because there is no carrier present; then do an open() call on the new (carrier- ignoring) device, which will succeed, send a dial command (if it's a smart-modem like a Hayes(tm) or USRobotics(tm)), and close the new device. When the dial completes, the original open will proceed. Because of the structure of the open code, this will all work correctly... and it is exactly how the original ACU code in UUCP works. For this reason, you can treat the new device as a call-dialing unit, if you want. Following are the required changes. The files with the suffix .noacu are the original files; the ones without the suffix are the revised files. In addition, you must add the line acu to your configuration file to be processed by mkconf. It uses the device addresses & other parameters supplied by the normal tty definition, and thus neither requires nor accepts any of its own. You also must use mknod to create an inode with the proper major and minor device numbers in the /dev directory. Check the output from mkconf to determine the major device number (probably 25); the minor device number is the same as for the original tty device for that line. Incidentally, this code also contains a correction for a bug in the original tty handlers, in which device address arrays were improperly indexed using the entire device id, rather than just the minor device id. ---------- *** mkconf.c.noacu Wed Jan 30 16:51:09 1985 --- mkconf.c Wed Jan 30 16:50:58 1985 *************** *** 639,644 } , /* Null name marks end of table */ { --- 639,663 ----- } , + /* Comms Mux, PALS or PASLA with open on no-carrier (for ACUs) */ + + { + "acu", CDEV+CONSDEV, MAXVDU, 1, + { + 0 } + , + { + "acuopen", "vduclose", "vduread", "vduwrite", "vduioctl", + "vdustop", "vdu" } + , + { + "vdurint", "vduxint" } + , + { + 0 } + , + } + , /* Null name marks end of table */ { *************** *** 1103,1108 continue; } if (!strcmp(dp->d_name,"pts")) continue; printf("struct tty %s[%d];\n", dp->d_csw[6], dp->d_ndev); --- 1122,1129 ----- continue; } if (!strcmp(dp->d_name,"pts")) + continue; + if (!strcmp(dp->d_name,"acu")) continue; printf("struct tty %s[%d];\n", dp->d_csw[6], dp->d_ndev); *** tty.c.noacu Wed Jan 30 16:42:30 1985 --- tty.c Wed Jan 30 16:41:48 1985 *************** *** 413,419 spl5(); while ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { ! if ((tp->t_state&CARR_ON)==0 || tp->t_chan!=NULL) { return(0); } sleep((caddr_t)&tp->t_rawq, TTIPRI); --- 452,458 ----- spl5(); while ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { ! if ((tp->t_state&(CARR_ON|DKCALL))==0 || tp->t_chan!=NULL) { return(0); } sleep((caddr_t)&tp->t_rawq, TTIPRI); *************** *** 768,774 register struct tty *tp; { ! if ((tp->t_state&CARR_ON)==0) return(0); if (tp->t_canq.c_cc || canon(tp)) while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) --- 807,813 ----- register struct tty *tp; { ! if ((tp->t_state&(CARR_ON|DKCALL))==0) return(0); if (tp->t_canq.c_cc || canon(tp)) while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) *************** *** 792,798 register c; #endif ! if ((tp->t_state&CARR_ON)==0) return(NULL); while (u.u_count) { #ifdef CGL_CBLK --- 831,837 ----- register c; #endif ! if ((tp->t_state&(CARR_ON|DKCALL))==0) return(NULL); while (u.u_count) { #ifdef CGL_CBLK *** vdu.c.noacu Wed Jan 30 16:42:07 1985 --- vdu.c Wed Jan 30 16:41:58 1985 *************** *** 2,7 * Vdu driver -- local terminal on PALS * * - uses Autodriver Channel for output * */ --- 2,9 ----- * Vdu driver -- local terminal on PALS * * - uses Autodriver Channel for output + * - with "acu" device open routines for opening Hayes-compatible + * autodial modems when no carrier detect is present JER 1/4/85 * */ *************** *** 77,82 */ vduopen(dev) { register struct tty *tp; if ((minor(dev) >= nvdu) || ( minor(dev) >= MAXVDU )) { --- 79,94 ----- */ vduopen(dev) { + xvduopen(dev,1); + } + + acuopen(dev) + { + xvduopen(dev,0); + } + + xvduopen(dev,carr) + { register struct tty *tp; if ((minor(dev) >= nvdu) || ( minor(dev) >= MAXVDU )) { *************** *** 96,103 vduenab(tp); } spl4(); ! while (!(tp->t_state&CARR_ON)) ! sleep(&tp->t_rawq, TTIPRI); spl0(); if ((tp->t_state&XCLUDE) && u.u_uid != 0) { u.u_error = EBUSY; --- 108,120 ----- vduenab(tp); } spl4(); ! if (carr) { ! while (!(tp->t_state&CARR_ON)) ! sleep(&tp->t_rawq, TTIPRI); ! tp->t_state &= ~DKCALL; /* JER flag non-dial-out */ ! } ! else ! tp->t_state |= DKCALL; /* JER flag dial-out mode */ spl0(); if ((tp->t_state&XCLUDE) && u.u_uid != 0) { u.u_error = EBUSY; *************** *** 174,180 struct tty *atp; { register struct tty *tp; ! register c, waddr; register struct ccb *ccb; tp = atp; --- 191,197 ----- struct tty *atp; { register struct tty *tp; ! register c, waddr,dkc; register struct ccb *ccb; tp = atp; *************** *** 178,184 register struct ccb *ccb; tp = atp; ! waddr = vduaddr[tp->t_dev] + 1; trace(1<<16, "vdustart", waddr); if ((tp->t_state&(TIMEOUT|TTSTOP|BUSY|CARR_ON)) != CARR_ON || (c = getc(&tp->t_outq)) < 0) --- 195,201 ----- register struct ccb *ccb; tp = atp; ! waddr = vduaddr[minor(tp->t_dev)] + 1; trace(1<<16, "vdustart", waddr); dkc = (tp->t_state&DKCALL)? 0: CARR_ON; /* JER CARR ck only if not acu */ if ((tp->t_state&(TIMEOUT|TTSTOP|BUSY|dkc)) != dkc *************** *** 180,186 tp = atp; waddr = vduaddr[tp->t_dev] + 1; trace(1<<16, "vdustart", waddr); ! if ((tp->t_state&(TIMEOUT|TTSTOP|BUSY|CARR_ON)) != CARR_ON || (c = getc(&tp->t_outq)) < 0) return; if (c > 0177 && (tp->t_flags&RAW) == 0) { --- 197,204 ----- tp = atp; waddr = vduaddr[minor(tp->t_dev)] + 1; trace(1<<16, "vdustart", waddr); ! dkc = (tp->t_state&DKCALL)? 0: CARR_ON; /* JER CARR ck only if not acu */ ! if ((tp->t_state&(TIMEOUT|TTSTOP|BUSY|dkc)) != dkc || (c = getc(&tp->t_outq)) < 0) return; if (c > 0177 && (tp->t_flags&RAW) == 0) { *************** *** 240,247 register struct tty *tp; register char c; ! tp = &vdu[dev]; ! raddr = vduaddr[dev]; if (!(tp->t_state & ISOPEN)) return; --- 258,265 ----- register struct tty *tp; register char c; ! tp = &vdu[minor(dev)]; ! raddr = vduaddr[minor(dev)]; if (!(tp->t_state & ISOPEN)) return; *************** *** 253,263 if (stat & CARR_OFF) { if (tp->t_state & CARR_ON) { ! if (tp->t_chan) ! scontrol(tp->t_chan, M_SIG, SIGHUP); ! else ! signal(tp->t_pgrp, SIGHUP); ! flushtty(tp); } tp->t_state &= ~CARR_ON; return; --- 271,286 ----- if (stat & CARR_OFF) { if (tp->t_state & CARR_ON) { ! if (!(tp->t_state & DKCALL)) { ! if (tp->t_chan) ! scontrol(tp->t_chan, M_SIG, SIGHUP); ! else ! signal(tp->t_pgrp, SIGHUP); ! flushtty(tp); ! tp->t_state &= ~CARR_ON; ! return; ! } ! tp->t_state &= ~CARR_ON; } } else { *************** *** 259,266 signal(tp->t_pgrp, SIGHUP); flushtty(tp); } - tp->t_state &= ~CARR_ON; - return; } if (!(tp->t_state & CARR_ON)) { tp->t_state |= CARR_ON; --- 282,287 ----- } tp->t_state &= ~CARR_ON; } } else { if (!(tp->t_state & CARR_ON)) { *************** *** 262,271 tp->t_state &= ~CARR_ON; return; } ! if (!(tp->t_state & CARR_ON)) { ! tp->t_state |= CARR_ON; ! wakeup(&tp->t_rawq); ! return; } if (stat & EXA) { /* --- 283,294 ----- tp->t_state &= ~CARR_ON; } } ! else { ! if (!(tp->t_state & CARR_ON)) { ! tp->t_state |= CARR_ON; ! wakeup(&tp->t_rawq); ! return; ! } } if (stat & EXA) { /* *************** *** 295,302 register struct ccb *ccb; register c; ! tp = &vdu[dev]; ! waddr = vduaddr[dev] + 1; if (!(tp->t_state & ISOPEN)) return; trace(1<<16, "wint", waddr); --- 318,325 ----- register struct ccb *ccb; register c; ! tp = &vdu[minor(dev)]; ! waddr = vduaddr[minor(dev)] + 1; if (!(tp->t_state & ISOPEN)) return; trace(1<<16, "wint", waddr); ---------------- J. Eric Roskos Perkin-Elmer Corp. Southern Development Center <jer@peora.UUCP>