1*17561Sbloom /* dh.c 6.6 84/12/20 */ 213Sbill 31934Swnj #include "dh.h" 42643Swnj #if NDH > 0 513Sbill /* 62479Swnj * DH-11/DM-11 driver 713Sbill */ 89771Ssam #include "../machine/pte.h" 99771Ssam 102730Swnj #include "bk.h" 1116062Skarels #include "uba.h" 1217122Sbloom #include "param.h" 1317122Sbloom #include "conf.h" 1417122Sbloom #include "dir.h" 1517122Sbloom #include "user.h" 1617122Sbloom #include "proc.h" 1717122Sbloom #include "ioctl.h" 1817122Sbloom #include "tty.h" 1917122Sbloom #include "map.h" 2017122Sbloom #include "buf.h" 2117122Sbloom #include "vm.h" 2217122Sbloom #include "kernel.h" 238472Sroot 2417122Sbloom #include "ubareg.h" 2517122Sbloom #include "ubavar.h" 2617122Sbloom #include "dhreg.h" 2717122Sbloom #include "dmreg.h" 288472Sroot 2917122Sbloom #include "bkmac.h" 3017122Sbloom #include "clist.h" 3117122Sbloom #include "file.h" 3217122Sbloom #include "uio.h" 3313Sbill 342468Swnj /* 352479Swnj * Definition of the driver for the auto-configuration program. 362479Swnj * There is one definition for the dh and one for the dm. 372468Swnj */ 3816190Skarels int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer(); 392974Swnj struct uba_device *dhinfo[NDH]; 402395Swnj u_short dhstd[] = { 0 }; 412395Swnj struct uba_driver dhdriver = 422605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 432395Swnj 442605Swnj int dmprobe(), dmattach(), dmintr(); 452974Swnj struct uba_device *dminfo[NDH]; 462479Swnj u_short dmstd[] = { 0 }; 472479Swnj struct uba_driver dmdriver = 482605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4913Sbill 506615Ssam #ifndef PORTSELECTOR 516615Ssam #define ISPEED B300 526615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 536615Ssam #else 546615Ssam #define ISPEED B4800 556615Ssam #define IFLAGS (EVENP|ODDP) 566615Ssam #endif 576615Ssam 5816190Skarels #define FASTTIMER (hz/30) /* scan rate with silos on */ 5916190Skarels 6013Sbill /* 612479Swnj * Local variables for the driver 6213Sbill */ 632643Swnj short dhsar[NDH]; /* software copy of last bar */ 642643Swnj short dhsoftCAR[NDH]; 6513Sbill 662643Swnj struct tty dh11[NDH*16]; 672643Swnj int ndh11 = NDH*16; 682479Swnj int dhact; /* mask of active dh's */ 6916190Skarels int dhsilos; /* mask of dh's with silo in use */ 7016190Skarels int dhchars[NDH]; /* recent input count */ 7116190Skarels int dhrate[NDH]; /* smoothed input count */ 7216190Skarels int dhhighrate = 100; /* silo on if dhchars > dhhighrate */ 7316190Skarels int dhlowrate = 75; /* silo off if dhrate < dhlowrate */ 7416190Skarels static short timerstarted; 752479Swnj int dhstart(), ttrstrt(); 7613Sbill 772479Swnj /* 782479Swnj * The clist space is mapped by the driver onto each UNIBUS. 792479Swnj * The UBACVT macro converts a clist space address for unibus uban 802479Swnj * into an i/o space address for the DMA routine. 812479Swnj */ 8216062Skarels int dh_ubinfo[NUBA]; /* info about allocated unibus map */ 8316062Skarels int cbase[NUBA]; /* base address in unibus map */ 842479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 8513Sbill 862456Swnj /* 872456Swnj * Routine for configuration to force a dh to interrupt. 882456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 892456Swnj */ 902468Swnj /*ARGSUSED*/ 912605Swnj dhprobe(reg) 922395Swnj caddr_t reg; 932395Swnj { 942468Swnj register int br, cvec; /* these are ``value-result'' */ 952479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 962395Swnj 972605Swnj #ifdef lint 982605Swnj br = 0; cvec = br; br = cvec; 997384Sroot if (ndh11 == 0) ndh11 = 1; 1004932Swnj dhrint(0); dhxint(0); 1012605Swnj #endif 1022696Swnj #ifndef notdef 1032566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1046380Swnj DELAY(1000); 1057384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1062566Swnj dhaddr->un.dhcsr = 0; 1072566Swnj #else 1082456Swnj dhaddr->un.dhcsr = DH_TIE; 1092456Swnj DELAY(5); 1102456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1112421Skre dhaddr->dhbcr = -1; 1122456Swnj dhaddr->dhcar = 0; 1132421Skre dhaddr->dhbar = 1; 1142456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1152421Skre dhaddr->un.dhcsr = 0; 1162456Swnj if (cvec && cvec != 0x200) 1172456Swnj cvec -= 4; /* transmit -> receive */ 1182482Swnj #endif 1197408Skre return (sizeof (struct dhdevice)); 1202395Swnj } 1212395Swnj 1222456Swnj /* 1232605Swnj * Routine called to attach a dh. 1242456Swnj */ 1252605Swnj dhattach(ui) 1262974Swnj struct uba_device *ui; 1272395Swnj { 1282395Swnj 1292566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1302395Swnj } 1312395Swnj 13213Sbill /* 1332479Swnj * Configuration routine to cause a dm to interrupt. 1342479Swnj */ 1352605Swnj dmprobe(reg) 1362605Swnj caddr_t reg; 1372479Swnj { 1382479Swnj register int br, vec; /* value-result */ 1392605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1402479Swnj 1412605Swnj #ifdef lint 1423101Swnj br = 0; vec = br; br = vec; 1436185Ssam dmintr(0); 1442605Swnj #endif 1452479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1462479Swnj DELAY(20); 1472479Swnj dmaddr->dmcsr = 0; 1482605Swnj return (1); 1492479Swnj } 1502479Swnj 1512605Swnj /*ARGSUSED*/ 1522605Swnj dmattach(ui) 1532974Swnj struct uba_device *ui; 1542479Swnj { 1552479Swnj 1562479Swnj /* no local state to set up */ 1572479Swnj } 1582479Swnj 1592479Swnj /* 1602468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1612468Swnj * is the first dh on this uba. Turn on this dh if this is 1622468Swnj * the first use of it. Also do a dmopen to wait for carrier. 16313Sbill */ 16413Sbill /*ARGSUSED*/ 16513Sbill dhopen(dev, flag) 1662395Swnj dev_t dev; 16713Sbill { 16813Sbill register struct tty *tp; 1692395Swnj register int unit, dh; 1702479Swnj register struct dhdevice *addr; 1712974Swnj register struct uba_device *ui; 17213Sbill int s; 17313Sbill 1742395Swnj unit = minor(dev); 1752395Swnj dh = unit >> 4; 1768566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 1778566Sroot return (ENXIO); 1782395Swnj tp = &dh11[unit]; 1798566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1808566Sroot return (EBUSY); 1812479Swnj addr = (struct dhdevice *)ui->ui_addr; 18213Sbill tp->t_addr = (caddr_t)addr; 18313Sbill tp->t_oproc = dhstart; 1845406Swnj tp->t_state |= TS_WOPEN; 1852468Swnj /* 1862468Swnj * While setting up state for this uba and this dh, 1872468Swnj * block uba resets which can clear the state. 1882468Swnj */ 1892468Swnj s = spl5(); 1902421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 191717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1922395Swnj dh_ubinfo[ui->ui_ubanum] = 1932421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 1942770Swnj 512+nclist*sizeof(struct cblock), 0); 1952456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 19613Sbill } 19716190Skarels if (timerstarted == 0) { 19816190Skarels timerstarted++; 19916190Skarels timeout(dhtimer, (caddr_t) 0, hz); 20016190Skarels } 2012456Swnj if ((dhact&(1<<dh)) == 0) { 2022456Swnj addr->un.dhcsr |= DH_IE; 2032468Swnj dhact |= (1<<dh); 20416190Skarels addr->dhsilo = 0; 2052456Swnj } 20613Sbill splx(s); 2072468Swnj /* 2082468Swnj * If this is first open, initialze tty state to default. 2092468Swnj */ 2105406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 21113Sbill ttychars(tp); 2126615Ssam #ifndef PORTSELECTOR 213168Sbill if (tp->t_ispeed == 0) { 2146615Ssam #endif 2156615Ssam tp->t_ispeed = ISPEED; 2166615Ssam tp->t_ospeed = ISPEED; 2176615Ssam tp->t_flags = IFLAGS; 2186615Ssam #ifndef PORTSELECTOR 219168Sbill } 2206615Ssam #endif 2212395Swnj dhparam(unit); 22213Sbill } 2232468Swnj /* 2242468Swnj * Wait for carrier, then process line discipline specific open. 2252468Swnj */ 22613Sbill dmopen(dev); 2278566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 22813Sbill } 22913Sbill 23013Sbill /* 2312468Swnj * Close a DH11 line, turning off the DM11. 23213Sbill */ 23313Sbill /*ARGSUSED*/ 23413Sbill dhclose(dev, flag) 2352395Swnj dev_t dev; 2362395Swnj int flag; 23713Sbill { 23813Sbill register struct tty *tp; 2392395Swnj register unit; 24013Sbill 2412395Swnj unit = minor(dev); 2422395Swnj tp = &dh11[unit]; 24313Sbill (*linesw[tp->t_line].l_close)(tp); 2442479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2455406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2462479Swnj dmctl(unit, DML_OFF, DMSET); 24713Sbill ttyclose(tp); 24813Sbill } 24913Sbill 2507725Sroot dhread(dev, uio) 2512395Swnj dev_t dev; 2527725Sroot struct uio *uio; 25313Sbill { 2548490Sroot register struct tty *tp = &dh11[minor(dev)]; 25513Sbill 2567725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 25713Sbill } 25813Sbill 2597831Sroot dhwrite(dev, uio) 2602395Swnj dev_t dev; 2617831Sroot struct uio *uio; 26213Sbill { 2638490Sroot register struct tty *tp = &dh11[minor(dev)]; 26413Sbill 2658490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 26613Sbill } 26713Sbill 26813Sbill /* 26913Sbill * DH11 receiver interrupt. 27013Sbill */ 2712395Swnj dhrint(dh) 2722395Swnj int dh; 27313Sbill { 27413Sbill register struct tty *tp; 2752395Swnj register c; 2762479Swnj register struct dhdevice *addr; 277117Sbill register struct tty *tp0; 2782974Swnj register struct uba_device *ui; 2792924Swnj int overrun = 0; 28013Sbill 2812395Swnj ui = dhinfo[dh]; 2822479Swnj if (ui == 0 || ui->ui_alive == 0) 2832479Swnj return; 2842479Swnj addr = (struct dhdevice *)ui->ui_addr; 2852468Swnj tp0 = &dh11[dh<<4]; 2862468Swnj /* 2872468Swnj * Loop fetching characters from the silo for this 2882468Swnj * dh until there are no more in the silo. 2892468Swnj */ 2902468Swnj while ((c = addr->dhrcr) < 0) { 2912468Swnj tp = tp0 + ((c>>8)&0xf); 29216190Skarels dhchars[dh]++; 2936615Ssam #ifndef PORTSELECTOR 2945406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 2956615Ssam #else 2966615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 2976615Ssam #endif 29813Sbill wakeup((caddr_t)tp); 29913Sbill continue; 30013Sbill } 3012468Swnj if (c & DH_PE) 30213Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 30313Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 30413Sbill continue; 3052924Swnj if ((c & DH_DO) && overrun == 0) { 3062924Swnj printf("dh%d: silo overflow\n", dh); 3072924Swnj overrun = 1; 3082924Swnj } 3092468Swnj if (c & DH_FE) 3102468Swnj /* 3112468Swnj * At framing error (break) generate 3122468Swnj * a null (in raw mode, for getty), or a 3132468Swnj * interrupt (in cooked/cbreak mode). 3142468Swnj */ 31513Sbill if (tp->t_flags&RAW) 3162468Swnj c = 0; 31713Sbill else 3189549Ssam c = tp->t_intrc; 3192730Swnj #if NBK > 0 320139Sbill if (tp->t_line == NETLDISC) { 321117Sbill c &= 0177; 322168Sbill BKINPUT(c, tp); 323117Sbill } else 3242730Swnj #endif 3252468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 32613Sbill } 32713Sbill } 32813Sbill 32913Sbill /* 3302468Swnj * Ioctl for DH11. 33113Sbill */ 33213Sbill /*ARGSUSED*/ 3337629Ssam dhioctl(dev, cmd, data, flag) 3347629Ssam caddr_t data; 33513Sbill { 33613Sbill register struct tty *tp; 3378566Sroot register int unit = minor(dev); 3388566Sroot int error; 33913Sbill 3402395Swnj tp = &dh11[unit]; 3418566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3428566Sroot if (error >= 0) 3438566Sroot return (error); 3448566Sroot error = ttioctl(tp, cmd, data, flag); 3458566Sroot if (error >= 0) { 346*17561Sbloom if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 347*17561Sbloom cmd == TIOCLBIC || cmd == TIOCLSET) 3482395Swnj dhparam(unit); 3498566Sroot return (error); 3508566Sroot } 3518566Sroot switch (cmd) { 3527629Ssam 353168Sbill case TIOCSBRK: 3542479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 355168Sbill break; 3567629Ssam 357168Sbill case TIOCCBRK: 3582479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 359168Sbill break; 3607629Ssam 361168Sbill case TIOCSDTR: 3622479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 363168Sbill break; 3647629Ssam 365168Sbill case TIOCCDTR: 3662479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 367168Sbill break; 3687629Ssam 369168Sbill default: 3708566Sroot return (ENOTTY); 371168Sbill } 3728566Sroot return (0); 37313Sbill } 37413Sbill 37513Sbill /* 37613Sbill * Set parameters from open or stty into the DH hardware 37713Sbill * registers. 37813Sbill */ 3792395Swnj dhparam(unit) 3802395Swnj register int unit; 38113Sbill { 38213Sbill register struct tty *tp; 3832479Swnj register struct dhdevice *addr; 3842395Swnj register int lpar; 385300Sbill int s; 38613Sbill 3872395Swnj tp = &dh11[unit]; 3882479Swnj addr = (struct dhdevice *)tp->t_addr; 3892468Swnj /* 3902468Swnj * Block interrupts so parameters will be set 3912468Swnj * before the line interrupts. 3922468Swnj */ 393300Sbill s = spl5(); 3942468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 39513Sbill if ((tp->t_ispeed)==0) { 3965406Swnj tp->t_state |= TS_HUPCLS; 3972479Swnj dmctl(unit, DML_OFF, DMSET); 39813Sbill return; 39913Sbill } 4002395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4012468Swnj if ((tp->t_ispeed) == B134) 4022395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4039549Ssam else if (tp->t_flags & (RAW|LITOUT)) 4042395Swnj lpar |= BITS8; 40513Sbill else 4062395Swnj lpar |= BITS7|PENABLE; 40713Sbill if ((tp->t_flags&EVENP) == 0) 4082395Swnj lpar |= OPAR; 4092468Swnj if ((tp->t_ospeed) == B110) 4102395Swnj lpar |= TWOSB; 4112395Swnj addr->dhlpr = lpar; 412300Sbill splx(s); 41313Sbill } 41413Sbill 41513Sbill /* 41613Sbill * DH11 transmitter interrupt. 41713Sbill * Restart each line which used to be active but has 41813Sbill * terminated transmission since the last interrupt. 41913Sbill */ 4202395Swnj dhxint(dh) 4212395Swnj int dh; 42213Sbill { 42313Sbill register struct tty *tp; 4242479Swnj register struct dhdevice *addr; 42513Sbill short ttybit, bar, *sbar; 4262974Swnj register struct uba_device *ui; 4272468Swnj register int unit; 4282605Swnj u_short cntr; 42913Sbill 4302395Swnj ui = dhinfo[dh]; 4312479Swnj addr = (struct dhdevice *)ui->ui_addr; 4322456Swnj if (addr->un.dhcsr & DH_NXM) { 4332456Swnj addr->un.dhcsr |= DH_CNI; 4342924Swnj printf("dh%d: NXM\n", dh); 435105Sbill } 4362395Swnj sbar = &dhsar[dh]; 43713Sbill bar = *sbar & ~addr->dhbar; 4382395Swnj unit = dh * 16; ttybit = 1; 4392468Swnj addr->un.dhcsr &= (short)~DH_TI; 4402468Swnj for (; bar; unit++, ttybit <<= 1) { 4412468Swnj if (bar & ttybit) { 44213Sbill *sbar &= ~ttybit; 44313Sbill bar &= ~ttybit; 4442395Swnj tp = &dh11[unit]; 4455406Swnj tp->t_state &= ~TS_BUSY; 4465406Swnj if (tp->t_state&TS_FLUSH) 4475406Swnj tp->t_state &= ~TS_FLUSH; 448113Sbill else { 4492456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4502468Swnj /* 4512468Swnj * Do arithmetic in a short to make up 4522468Swnj * for lost 16&17 bits. 4532468Swnj */ 4542605Swnj cntr = addr->dhcar - 4552468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4563101Swnj ndflush(&tp->t_outq, (int)cntr); 457113Sbill } 458113Sbill if (tp->t_line) 45913Sbill (*linesw[tp->t_line].l_start)(tp); 460113Sbill else 46113Sbill dhstart(tp); 46213Sbill } 46313Sbill } 46413Sbill } 46513Sbill 46613Sbill /* 46713Sbill * Start (restart) transmission on the given DH11 line. 46813Sbill */ 46913Sbill dhstart(tp) 4702395Swnj register struct tty *tp; 47113Sbill { 4722479Swnj register struct dhdevice *addr; 4732468Swnj register int car, dh, unit, nch; 4742395Swnj int s; 47513Sbill 4762468Swnj unit = minor(tp->t_dev); 4772468Swnj dh = unit >> 4; 4782468Swnj unit &= 0xf; 4792479Swnj addr = (struct dhdevice *)tp->t_addr; 4802468Swnj 48113Sbill /* 4822468Swnj * Must hold interrupts in following code to prevent 4832468Swnj * state of the tp from changing. 48413Sbill */ 48513Sbill s = spl5(); 4862468Swnj /* 4872468Swnj * If it's currently active, or delaying, no need to do anything. 4882468Swnj */ 4895406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 49013Sbill goto out; 4912468Swnj /* 4922468Swnj * If there are sleepers, and output has drained below low 4932468Swnj * water mark, wake up the sleepers. 4942468Swnj */ 4955406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 4965406Swnj if (tp->t_state&TS_ASLEEP) { 4975406Swnj tp->t_state &= ~TS_ASLEEP; 4985406Swnj wakeup((caddr_t)&tp->t_outq); 4995406Swnj } 5005406Swnj if (tp->t_wsel) { 5015406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5025406Swnj tp->t_wsel = 0; 5035406Swnj tp->t_state &= ~TS_WCOLL; 5045406Swnj } 50513Sbill } 5062468Swnj /* 5072468Swnj * Now restart transmission unless the output queue is 5082468Swnj * empty. 5092468Swnj */ 51013Sbill if (tp->t_outq.c_cc == 0) 51113Sbill goto out; 5129549Ssam if (tp->t_flags & (RAW|LITOUT)) 51313Sbill nch = ndqb(&tp->t_outq, 0); 5142395Swnj else { 51513Sbill nch = ndqb(&tp->t_outq, 0200); 5162468Swnj /* 5172468Swnj * If first thing on queue is a delay process it. 5182468Swnj */ 51913Sbill if (nch == 0) { 52013Sbill nch = getc(&tp->t_outq); 5212468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5225406Swnj tp->t_state |= TS_TIMEOUT; 52313Sbill goto out; 52413Sbill } 52513Sbill } 5262468Swnj /* 5272468Swnj * If characters to transmit, restart transmission. 5282468Swnj */ 52913Sbill if (nch) { 5302468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5312468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5323586Sroot /* 5333586Sroot * The following nonsense with short word 5343586Sroot * is to make sure the dhbar |= word below 5353586Sroot * is done with an interlocking bisw2 instruction. 5363586Sroot */ 5373586Sroot { short word = 1 << unit; 5383586Sroot dhsar[dh] |= word; 5392468Swnj addr->dhcar = car; 54013Sbill addr->dhbcr = -nch; 5413586Sroot addr->dhbar |= word; 5423586Sroot } 5435406Swnj tp->t_state |= TS_BUSY; 54413Sbill } 5452395Swnj out: 54613Sbill splx(s); 54713Sbill } 54813Sbill 54913Sbill /* 5502468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 55113Sbill */ 55213Sbill /*ARGSUSED*/ 55313Sbill dhstop(tp, flag) 5542468Swnj register struct tty *tp; 55513Sbill { 5562479Swnj register struct dhdevice *addr; 5572395Swnj register int unit, s; 55813Sbill 5592479Swnj addr = (struct dhdevice *)tp->t_addr; 5602468Swnj /* 5612468Swnj * Block input/output interrupts while messing with state. 5622468Swnj */ 5632468Swnj s = spl5(); 5645406Swnj if (tp->t_state & TS_BUSY) { 5652468Swnj /* 5662468Swnj * Device is transmitting; stop output 5672468Swnj * by selecting the line and setting the byte 5682468Swnj * count to -1. We will clean up later 5692468Swnj * by examining the address where the dh stopped. 5702468Swnj */ 5712395Swnj unit = minor(tp->t_dev); 5722456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5735406Swnj if ((tp->t_state&TS_TTSTOP)==0) 5745406Swnj tp->t_state |= TS_FLUSH; 575113Sbill addr->dhbcr = -1; 576113Sbill } 57713Sbill splx(s); 57813Sbill } 57913Sbill 580168Sbill /* 581280Sbill * Reset state of driver if UBA reset was necessary. 582280Sbill * Reset the csrl and lpr registers on open lines, and 583280Sbill * restart transmitters. 584280Sbill */ 5852395Swnj dhreset(uban) 5862468Swnj int uban; 587280Sbill { 5882395Swnj register int dh, unit; 589280Sbill register struct tty *tp; 5902974Swnj register struct uba_device *ui; 5912421Skre int i; 592280Sbill 5932421Skre if (dh_ubinfo[uban] == 0) 5942421Skre return; 5952421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 5962770Swnj 512+nclist*sizeof (struct cblock), 0); 5972421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 5982395Swnj dh = 0; 5992643Swnj for (dh = 0; dh < NDH; dh++) { 6002421Skre ui = dhinfo[dh]; 6012421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6022421Skre continue; 6032924Swnj printf(" dh%d", dh); 6042479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 60516190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; 6062421Skre unit = dh * 16; 6072421Skre for (i = 0; i < 16; i++) { 6082421Skre tp = &dh11[unit]; 6095406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6102421Skre dhparam(unit); 6112479Swnj dmctl(unit, DML_ON, DMSET); 6125406Swnj tp->t_state &= ~TS_BUSY; 6132421Skre dhstart(tp); 6142421Skre } 6152421Skre unit++; 616300Sbill } 617300Sbill } 61816190Skarels dhsilos = 0; 619280Sbill } 6202395Swnj 62116190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 6222468Swnj /* 62316190Skarels * At software clock interrupt time, check status. 62416190Skarels * Empty all the dh silos that are in use, and decide whether 62516190Skarels * to turn any silos off or on. 6262468Swnj */ 6272456Swnj dhtimer() 6282456Swnj { 62916190Skarels register int dh, s; 63016190Skarels static int timercalls; 6312456Swnj 63216190Skarels if (dhsilos) { 63316190Skarels dhfasttimers++; /*DEBUG*/ 63416190Skarels timercalls++; 63516190Skarels s = spl5(); 63616190Skarels for (dh = 0; dh < NDH; dh++) 63716190Skarels if (dhsilos & (1 << dh)) 63816190Skarels dhrint(dh); 63916190Skarels splx(s); 64016190Skarels } 64116190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 64216190Skarels dhslowtimers++; /*DEBUG*/ 64316190Skarels timercalls = 0; 64416190Skarels for (dh = 0; dh < NDH; dh++) { 64516190Skarels ave(dhrate[dh], dhchars[dh], 8); 64616190Skarels if ((dhchars[dh] > dhhighrate) && 64716190Skarels ((dhsilos & (1 << dh)) == 0)) { 64816190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 64916190Skarels (dhchars[dh] > 500? 32 : 16); 65016190Skarels dhsilos |= (1 << dh); 65116190Skarels dhtransitions++; /*DEBUG*/ 65216190Skarels } else if ((dhsilos & (1 << dh)) && 65316190Skarels (dhrate[dh] < dhlowrate)) { 65416190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; 65516190Skarels dhsilos &= ~(1 << dh); 65616190Skarels } 65716190Skarels dhchars[dh] = 0; 65816190Skarels } 65916190Skarels } 66016190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); 6612456Swnj } 6622456Swnj 6632468Swnj /* 6642479Swnj * Turn on the line associated with dh dev. 6652468Swnj */ 6662468Swnj dmopen(dev) 6672468Swnj dev_t dev; 6682468Swnj { 6692468Swnj register struct tty *tp; 6702468Swnj register struct dmdevice *addr; 6712974Swnj register struct uba_device *ui; 6722468Swnj register int unit; 6732468Swnj register int dm; 6743792Swnj int s; 6752468Swnj 6762468Swnj unit = minor(dev); 6772479Swnj dm = unit >> 4; 6782468Swnj tp = &dh11[unit]; 6792566Swnj unit &= 0xf; 68016942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 6815406Swnj tp->t_state |= TS_CARR_ON; 6822468Swnj return; 6832468Swnj } 6842468Swnj addr = (struct dmdevice *)ui->ui_addr; 6853792Swnj s = spl5(); 6862479Swnj addr->dmcsr &= ~DM_SE; 6872479Swnj while (addr->dmcsr & DM_BUSY) 6882468Swnj ; 6892566Swnj addr->dmcsr = unit; 6902479Swnj addr->dmlstat = DML_ON; 69116942Skarels if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit))) 6925406Swnj tp->t_state |= TS_CARR_ON; 6933792Swnj addr->dmcsr = DM_IE|DM_SE; 6945406Swnj while ((tp->t_state&TS_CARR_ON)==0) 6952468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6963792Swnj splx(s); 6972468Swnj } 6982468Swnj 6992468Swnj /* 7002468Swnj * Dump control bits into the DM registers. 7012468Swnj */ 7022468Swnj dmctl(dev, bits, how) 7032468Swnj dev_t dev; 7042468Swnj int bits, how; 7052468Swnj { 7062974Swnj register struct uba_device *ui; 7072468Swnj register struct dmdevice *addr; 7082468Swnj register int unit, s; 7092468Swnj int dm; 7102468Swnj 7112468Swnj unit = minor(dev); 7122468Swnj dm = unit >> 4; 7132468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7142468Swnj return; 7152468Swnj addr = (struct dmdevice *)ui->ui_addr; 7162468Swnj s = spl5(); 7172479Swnj addr->dmcsr &= ~DM_SE; 7182479Swnj while (addr->dmcsr & DM_BUSY) 7192468Swnj ; 7202468Swnj addr->dmcsr = unit & 0xf; 7212468Swnj switch(how) { 7222468Swnj case DMSET: 7232468Swnj addr->dmlstat = bits; 7242468Swnj break; 7252468Swnj case DMBIS: 7262468Swnj addr->dmlstat |= bits; 7272468Swnj break; 7282468Swnj case DMBIC: 7292468Swnj addr->dmlstat &= ~bits; 7302468Swnj break; 7312468Swnj } 7323792Swnj addr->dmcsr = DM_IE|DM_SE; 7332468Swnj splx(s); 7342468Swnj } 7352468Swnj 7362468Swnj /* 7372468Swnj * DM11 interrupt; deal with carrier transitions. 7382468Swnj */ 7392468Swnj dmintr(dm) 7402468Swnj register int dm; 7412468Swnj { 7422974Swnj register struct uba_device *ui; 7432468Swnj register struct tty *tp; 7442468Swnj register struct dmdevice *addr; 74516942Skarels int unit; 7462468Swnj 7472468Swnj ui = dminfo[dm]; 7482479Swnj if (ui == 0) 7492479Swnj return; 7502468Swnj addr = (struct dmdevice *)ui->ui_addr; 7513997Sroot if (addr->dmcsr&DM_DONE) { 7523997Sroot if (addr->dmcsr&DM_CF) { 75316942Skarels unit = addr->dmcsr & 0xf; 75416942Skarels tp = &dh11[(dm << 4) + unit]; 7553997Sroot wakeup((caddr_t)&tp->t_rawq); 7569549Ssam if ((tp->t_state&TS_WOPEN) == 0 && 7579605Ssam (tp->t_flags & MDMBUF)) { 7583997Sroot if (addr->dmlstat & DML_CAR) { 7595406Swnj tp->t_state &= ~TS_TTSTOP; 7603997Sroot ttstart(tp); 7615406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7625406Swnj tp->t_state |= TS_TTSTOP; 7633997Sroot dhstop(tp, 0); 7643997Sroot } 7653997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7665406Swnj if ((tp->t_state&TS_WOPEN)==0 && 76716942Skarels (tp->t_flags & NOHANG) == 0 && 76816942Skarels (dhsoftCAR[dm] & (1<<unit)) == 0) { 7693997Sroot gsignal(tp->t_pgrp, SIGHUP); 7703997Sroot gsignal(tp->t_pgrp, SIGCONT); 7713997Sroot addr->dmlstat = 0; 77212775Ssam ttyflush(tp, FREAD|FWRITE); 7733997Sroot } 7745406Swnj tp->t_state &= ~TS_CARR_ON; 7753997Sroot } else 7765406Swnj tp->t_state |= TS_CARR_ON; 7773997Sroot } 7783997Sroot addr->dmcsr = DM_IE|DM_SE; 7792468Swnj } 7802468Swnj } 7812625Swnj #endif 782