Xref: utzoo comp.dcom.modems:1241 comp.sys.att:2213 comp.unix.questions:5182 Path: utzoo!utgpu!water!watmath!clyde!cbosgd!ihnp4!gargoyle!oddjob!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.dcom.modems,comp.sys.att,comp.unix.questions Subject: dial in / out on same line Summary: how to implement it Message-ID: <10330@mimsy.UUCP> Date: 25 Jan 88 07:21:54 GMT References: <142@mccc.UUCP> <564@virginia.acc.virginia.edu> <10321@mimsy.UUCP> <148@mccc.UUCP> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 124 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