1*21954Skarels /* dh.c 6.8 85/06/04 */ 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" 2318311Sralph #include "syslog.h" 248472Sroot 2517122Sbloom #include "ubareg.h" 2617122Sbloom #include "ubavar.h" 2717122Sbloom #include "dhreg.h" 2817122Sbloom #include "dmreg.h" 298472Sroot 3017122Sbloom #include "bkmac.h" 3117122Sbloom #include "clist.h" 3217122Sbloom #include "file.h" 3317122Sbloom #include "uio.h" 3413Sbill 352468Swnj /* 362479Swnj * Definition of the driver for the auto-configuration program. 372479Swnj * There is one definition for the dh and one for the dm. 382468Swnj */ 3916190Skarels int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer(); 402974Swnj struct uba_device *dhinfo[NDH]; 412395Swnj u_short dhstd[] = { 0 }; 422395Swnj struct uba_driver dhdriver = 432605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 442395Swnj 452605Swnj int dmprobe(), dmattach(), dmintr(); 462974Swnj struct uba_device *dminfo[NDH]; 472479Swnj u_short dmstd[] = { 0 }; 482479Swnj struct uba_driver dmdriver = 492605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 5013Sbill 516615Ssam #ifndef PORTSELECTOR 526615Ssam #define ISPEED B300 536615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 546615Ssam #else 556615Ssam #define ISPEED B4800 566615Ssam #define IFLAGS (EVENP|ODDP) 576615Ssam #endif 586615Ssam 5916190Skarels #define FASTTIMER (hz/30) /* scan rate with silos on */ 6016190Skarels 6113Sbill /* 622479Swnj * Local variables for the driver 6313Sbill */ 642643Swnj short dhsar[NDH]; /* software copy of last bar */ 652643Swnj short dhsoftCAR[NDH]; 6613Sbill 672643Swnj struct tty dh11[NDH*16]; 682643Swnj int ndh11 = NDH*16; 692479Swnj int dhact; /* mask of active dh's */ 7016190Skarels int dhsilos; /* mask of dh's with silo in use */ 7116190Skarels int dhchars[NDH]; /* recent input count */ 7216190Skarels int dhrate[NDH]; /* smoothed input count */ 7316190Skarels int dhhighrate = 100; /* silo on if dhchars > dhhighrate */ 7416190Skarels int dhlowrate = 75; /* silo off if dhrate < dhlowrate */ 7516190Skarels static short timerstarted; 762479Swnj int dhstart(), ttrstrt(); 7713Sbill 782479Swnj /* 792479Swnj * The clist space is mapped by the driver onto each UNIBUS. 802479Swnj * The UBACVT macro converts a clist space address for unibus uban 812479Swnj * into an i/o space address for the DMA routine. 822479Swnj */ 8316062Skarels int dh_ubinfo[NUBA]; /* info about allocated unibus map */ 8416062Skarels int cbase[NUBA]; /* base address in unibus map */ 852479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 8613Sbill 872456Swnj /* 882456Swnj * Routine for configuration to force a dh to interrupt. 892456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 902456Swnj */ 912468Swnj /*ARGSUSED*/ 922605Swnj dhprobe(reg) 932395Swnj caddr_t reg; 942395Swnj { 952468Swnj register int br, cvec; /* these are ``value-result'' */ 962479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 972395Swnj 982605Swnj #ifdef lint 992605Swnj br = 0; cvec = br; br = cvec; 1007384Sroot if (ndh11 == 0) ndh11 = 1; 1014932Swnj dhrint(0); dhxint(0); 1022605Swnj #endif 1032696Swnj #ifndef notdef 1042566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1056380Swnj DELAY(1000); 1067384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1072566Swnj dhaddr->un.dhcsr = 0; 1082566Swnj #else 1092456Swnj dhaddr->un.dhcsr = DH_TIE; 1102456Swnj DELAY(5); 1112456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1122421Skre dhaddr->dhbcr = -1; 1132456Swnj dhaddr->dhcar = 0; 1142421Skre dhaddr->dhbar = 1; 1152456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1162421Skre dhaddr->un.dhcsr = 0; 1172456Swnj if (cvec && cvec != 0x200) 1182456Swnj cvec -= 4; /* transmit -> receive */ 1192482Swnj #endif 1207408Skre return (sizeof (struct dhdevice)); 1212395Swnj } 1222395Swnj 1232456Swnj /* 1242605Swnj * Routine called to attach a dh. 1252456Swnj */ 1262605Swnj dhattach(ui) 1272974Swnj struct uba_device *ui; 1282395Swnj { 1292395Swnj 1302566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1312395Swnj } 1322395Swnj 13313Sbill /* 1342479Swnj * Configuration routine to cause a dm to interrupt. 1352479Swnj */ 1362605Swnj dmprobe(reg) 1372605Swnj caddr_t reg; 1382479Swnj { 1392479Swnj register int br, vec; /* value-result */ 1402605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1412479Swnj 1422605Swnj #ifdef lint 1433101Swnj br = 0; vec = br; br = vec; 1446185Ssam dmintr(0); 1452605Swnj #endif 1462479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1472479Swnj DELAY(20); 1482479Swnj dmaddr->dmcsr = 0; 1492605Swnj return (1); 1502479Swnj } 1512479Swnj 1522605Swnj /*ARGSUSED*/ 1532605Swnj dmattach(ui) 1542974Swnj struct uba_device *ui; 1552479Swnj { 1562479Swnj 1572479Swnj /* no local state to set up */ 1582479Swnj } 1592479Swnj 1602479Swnj /* 1612468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1622468Swnj * is the first dh on this uba. Turn on this dh if this is 1632468Swnj * the first use of it. Also do a dmopen to wait for carrier. 16413Sbill */ 16513Sbill /*ARGSUSED*/ 16613Sbill dhopen(dev, flag) 1672395Swnj dev_t dev; 16813Sbill { 16913Sbill register struct tty *tp; 1702395Swnj register int unit, dh; 1712479Swnj register struct dhdevice *addr; 1722974Swnj register struct uba_device *ui; 17313Sbill int s; 17413Sbill 1752395Swnj unit = minor(dev); 1762395Swnj dh = unit >> 4; 1778566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 1788566Sroot return (ENXIO); 1792395Swnj tp = &dh11[unit]; 1808566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1818566Sroot return (EBUSY); 1822479Swnj addr = (struct dhdevice *)ui->ui_addr; 18313Sbill tp->t_addr = (caddr_t)addr; 18413Sbill tp->t_oproc = dhstart; 1855406Swnj tp->t_state |= TS_WOPEN; 1862468Swnj /* 1872468Swnj * While setting up state for this uba and this dh, 1882468Swnj * block uba resets which can clear the state. 1892468Swnj */ 1902468Swnj s = spl5(); 1912421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 192717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1932395Swnj dh_ubinfo[ui->ui_ubanum] = 1942421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 1952770Swnj 512+nclist*sizeof(struct cblock), 0); 1962456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 19713Sbill } 19816190Skarels if (timerstarted == 0) { 19916190Skarels timerstarted++; 20016190Skarels timeout(dhtimer, (caddr_t) 0, hz); 20116190Skarels } 2022456Swnj if ((dhact&(1<<dh)) == 0) { 2032456Swnj addr->un.dhcsr |= DH_IE; 2042468Swnj dhact |= (1<<dh); 20516190Skarels addr->dhsilo = 0; 2062456Swnj } 20713Sbill splx(s); 2082468Swnj /* 2092468Swnj * If this is first open, initialze tty state to default. 2102468Swnj */ 2115406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 21213Sbill ttychars(tp); 2136615Ssam #ifndef PORTSELECTOR 214168Sbill if (tp->t_ispeed == 0) { 2156615Ssam #endif 2166615Ssam tp->t_ispeed = ISPEED; 2176615Ssam tp->t_ospeed = ISPEED; 2186615Ssam tp->t_flags = IFLAGS; 2196615Ssam #ifndef PORTSELECTOR 220168Sbill } 2216615Ssam #endif 2222395Swnj dhparam(unit); 22313Sbill } 2242468Swnj /* 2252468Swnj * Wait for carrier, then process line discipline specific open. 2262468Swnj */ 22713Sbill dmopen(dev); 2288566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 22913Sbill } 23013Sbill 23113Sbill /* 2322468Swnj * Close a DH11 line, turning off the DM11. 23313Sbill */ 23413Sbill /*ARGSUSED*/ 23513Sbill dhclose(dev, flag) 2362395Swnj dev_t dev; 2372395Swnj int flag; 23813Sbill { 23913Sbill register struct tty *tp; 2402395Swnj register unit; 24113Sbill 2422395Swnj unit = minor(dev); 2432395Swnj tp = &dh11[unit]; 24413Sbill (*linesw[tp->t_line].l_close)(tp); 2452479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2465406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2472479Swnj dmctl(unit, DML_OFF, DMSET); 24813Sbill ttyclose(tp); 24913Sbill } 25013Sbill 2517725Sroot dhread(dev, uio) 2522395Swnj dev_t dev; 2537725Sroot struct uio *uio; 25413Sbill { 2558490Sroot register struct tty *tp = &dh11[minor(dev)]; 25613Sbill 2577725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 25813Sbill } 25913Sbill 2607831Sroot dhwrite(dev, uio) 2612395Swnj dev_t dev; 2627831Sroot struct uio *uio; 26313Sbill { 2648490Sroot register struct tty *tp = &dh11[minor(dev)]; 26513Sbill 2668490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 26713Sbill } 26813Sbill 26913Sbill /* 27013Sbill * DH11 receiver interrupt. 27113Sbill */ 2722395Swnj dhrint(dh) 2732395Swnj int dh; 27413Sbill { 27513Sbill register struct tty *tp; 2762395Swnj register c; 2772479Swnj register struct dhdevice *addr; 278117Sbill register struct tty *tp0; 2792974Swnj register struct uba_device *ui; 2802924Swnj int overrun = 0; 28113Sbill 2822395Swnj ui = dhinfo[dh]; 2832479Swnj if (ui == 0 || ui->ui_alive == 0) 2842479Swnj return; 2852479Swnj addr = (struct dhdevice *)ui->ui_addr; 2862468Swnj tp0 = &dh11[dh<<4]; 2872468Swnj /* 2882468Swnj * Loop fetching characters from the silo for this 2892468Swnj * dh until there are no more in the silo. 2902468Swnj */ 2912468Swnj while ((c = addr->dhrcr) < 0) { 2922468Swnj tp = tp0 + ((c>>8)&0xf); 29316190Skarels dhchars[dh]++; 2946615Ssam #ifndef PORTSELECTOR 2955406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 2966615Ssam #else 2976615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 2986615Ssam #endif 29913Sbill wakeup((caddr_t)tp); 30013Sbill continue; 30113Sbill } 3022468Swnj if (c & DH_PE) 30313Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 30413Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 30513Sbill continue; 3062924Swnj if ((c & DH_DO) && overrun == 0) { 30718311Sralph log(KERN_RECOV, "dh%d: silo overflow\n", dh); 3082924Swnj overrun = 1; 3092924Swnj } 3102468Swnj if (c & DH_FE) 3112468Swnj /* 3122468Swnj * At framing error (break) generate 3132468Swnj * a null (in raw mode, for getty), or a 3142468Swnj * interrupt (in cooked/cbreak mode). 3152468Swnj */ 31613Sbill if (tp->t_flags&RAW) 3172468Swnj c = 0; 31813Sbill else 3199549Ssam c = tp->t_intrc; 3202730Swnj #if NBK > 0 321139Sbill if (tp->t_line == NETLDISC) { 322117Sbill c &= 0177; 323168Sbill BKINPUT(c, tp); 324117Sbill } else 3252730Swnj #endif 3262468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 32713Sbill } 32813Sbill } 32913Sbill 33013Sbill /* 3312468Swnj * Ioctl for DH11. 33213Sbill */ 33313Sbill /*ARGSUSED*/ 3347629Ssam dhioctl(dev, cmd, data, flag) 3357629Ssam caddr_t data; 33613Sbill { 33713Sbill register struct tty *tp; 3388566Sroot register int unit = minor(dev); 3398566Sroot int error; 34013Sbill 3412395Swnj tp = &dh11[unit]; 3428566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3438566Sroot if (error >= 0) 3448566Sroot return (error); 3458566Sroot error = ttioctl(tp, cmd, data, flag); 3468566Sroot if (error >= 0) { 34717561Sbloom if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 34817561Sbloom cmd == TIOCLBIC || cmd == TIOCLSET) 3492395Swnj dhparam(unit); 3508566Sroot return (error); 3518566Sroot } 3528566Sroot switch (cmd) { 3537629Ssam 354168Sbill case TIOCSBRK: 3552479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 356168Sbill break; 3577629Ssam 358168Sbill case TIOCCBRK: 3592479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 360168Sbill break; 3617629Ssam 362168Sbill case TIOCSDTR: 3632479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 364168Sbill break; 3657629Ssam 366168Sbill case TIOCCDTR: 3672479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 368168Sbill break; 3697629Ssam 370168Sbill default: 3718566Sroot return (ENOTTY); 372168Sbill } 3738566Sroot return (0); 37413Sbill } 37513Sbill 37613Sbill /* 37713Sbill * Set parameters from open or stty into the DH hardware 37813Sbill * registers. 37913Sbill */ 3802395Swnj dhparam(unit) 3812395Swnj register int unit; 38213Sbill { 38313Sbill register struct tty *tp; 3842479Swnj register struct dhdevice *addr; 3852395Swnj register int lpar; 386300Sbill int s; 38713Sbill 3882395Swnj tp = &dh11[unit]; 3892479Swnj addr = (struct dhdevice *)tp->t_addr; 3902468Swnj /* 3912468Swnj * Block interrupts so parameters will be set 3922468Swnj * before the line interrupts. 3932468Swnj */ 394300Sbill s = spl5(); 3952468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 39613Sbill if ((tp->t_ispeed)==0) { 3975406Swnj tp->t_state |= TS_HUPCLS; 3982479Swnj dmctl(unit, DML_OFF, DMSET); 39913Sbill return; 40013Sbill } 4012395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4022468Swnj if ((tp->t_ispeed) == B134) 4032395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4049549Ssam else if (tp->t_flags & (RAW|LITOUT)) 4052395Swnj lpar |= BITS8; 40613Sbill else 4072395Swnj lpar |= BITS7|PENABLE; 40813Sbill if ((tp->t_flags&EVENP) == 0) 4092395Swnj lpar |= OPAR; 4102468Swnj if ((tp->t_ospeed) == B110) 4112395Swnj lpar |= TWOSB; 4122395Swnj addr->dhlpr = lpar; 413300Sbill splx(s); 41413Sbill } 41513Sbill 41613Sbill /* 41713Sbill * DH11 transmitter interrupt. 41813Sbill * Restart each line which used to be active but has 41913Sbill * terminated transmission since the last interrupt. 42013Sbill */ 4212395Swnj dhxint(dh) 4222395Swnj int dh; 42313Sbill { 42413Sbill register struct tty *tp; 4252479Swnj register struct dhdevice *addr; 42613Sbill short ttybit, bar, *sbar; 4272974Swnj register struct uba_device *ui; 4282468Swnj register int unit; 4292605Swnj u_short cntr; 43013Sbill 4312395Swnj ui = dhinfo[dh]; 4322479Swnj addr = (struct dhdevice *)ui->ui_addr; 4332456Swnj if (addr->un.dhcsr & DH_NXM) { 4342456Swnj addr->un.dhcsr |= DH_CNI; 4352924Swnj printf("dh%d: NXM\n", dh); 436105Sbill } 4372395Swnj sbar = &dhsar[dh]; 43813Sbill bar = *sbar & ~addr->dhbar; 4392395Swnj unit = dh * 16; ttybit = 1; 4402468Swnj addr->un.dhcsr &= (short)~DH_TI; 4412468Swnj for (; bar; unit++, ttybit <<= 1) { 4422468Swnj if (bar & ttybit) { 44313Sbill *sbar &= ~ttybit; 44413Sbill bar &= ~ttybit; 4452395Swnj tp = &dh11[unit]; 4465406Swnj tp->t_state &= ~TS_BUSY; 4475406Swnj if (tp->t_state&TS_FLUSH) 4485406Swnj tp->t_state &= ~TS_FLUSH; 449113Sbill else { 4502456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4512468Swnj /* 4522468Swnj * Do arithmetic in a short to make up 4532468Swnj * for lost 16&17 bits. 4542468Swnj */ 4552605Swnj cntr = addr->dhcar - 4562468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4573101Swnj ndflush(&tp->t_outq, (int)cntr); 458113Sbill } 459113Sbill if (tp->t_line) 46013Sbill (*linesw[tp->t_line].l_start)(tp); 461113Sbill else 46213Sbill dhstart(tp); 46313Sbill } 46413Sbill } 46513Sbill } 46613Sbill 46713Sbill /* 46813Sbill * Start (restart) transmission on the given DH11 line. 46913Sbill */ 47013Sbill dhstart(tp) 4712395Swnj register struct tty *tp; 47213Sbill { 4732479Swnj register struct dhdevice *addr; 4742468Swnj register int car, dh, unit, nch; 4752395Swnj int s; 47613Sbill 4772468Swnj unit = minor(tp->t_dev); 4782468Swnj dh = unit >> 4; 4792468Swnj unit &= 0xf; 4802479Swnj addr = (struct dhdevice *)tp->t_addr; 4812468Swnj 48213Sbill /* 4832468Swnj * Must hold interrupts in following code to prevent 4842468Swnj * state of the tp from changing. 48513Sbill */ 48613Sbill s = spl5(); 4872468Swnj /* 4882468Swnj * If it's currently active, or delaying, no need to do anything. 4892468Swnj */ 4905406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 49113Sbill goto out; 4922468Swnj /* 4932468Swnj * If there are sleepers, and output has drained below low 4942468Swnj * water mark, wake up the sleepers. 4952468Swnj */ 4965406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 4975406Swnj if (tp->t_state&TS_ASLEEP) { 4985406Swnj tp->t_state &= ~TS_ASLEEP; 4995406Swnj wakeup((caddr_t)&tp->t_outq); 5005406Swnj } 5015406Swnj if (tp->t_wsel) { 5025406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5035406Swnj tp->t_wsel = 0; 5045406Swnj tp->t_state &= ~TS_WCOLL; 5055406Swnj } 50613Sbill } 5072468Swnj /* 5082468Swnj * Now restart transmission unless the output queue is 5092468Swnj * empty. 5102468Swnj */ 51113Sbill if (tp->t_outq.c_cc == 0) 51213Sbill goto out; 5139549Ssam if (tp->t_flags & (RAW|LITOUT)) 51413Sbill nch = ndqb(&tp->t_outq, 0); 5152395Swnj else { 51613Sbill nch = ndqb(&tp->t_outq, 0200); 5172468Swnj /* 5182468Swnj * If first thing on queue is a delay process it. 5192468Swnj */ 52013Sbill if (nch == 0) { 52113Sbill nch = getc(&tp->t_outq); 5222468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5235406Swnj tp->t_state |= TS_TIMEOUT; 52413Sbill goto out; 52513Sbill } 52613Sbill } 5272468Swnj /* 5282468Swnj * If characters to transmit, restart transmission. 5292468Swnj */ 53013Sbill if (nch) { 5312468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5322468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5333586Sroot /* 5343586Sroot * The following nonsense with short word 5353586Sroot * is to make sure the dhbar |= word below 5363586Sroot * is done with an interlocking bisw2 instruction. 5373586Sroot */ 5383586Sroot { short word = 1 << unit; 5393586Sroot dhsar[dh] |= word; 5402468Swnj addr->dhcar = car; 54113Sbill addr->dhbcr = -nch; 5423586Sroot addr->dhbar |= word; 5433586Sroot } 5445406Swnj tp->t_state |= TS_BUSY; 54513Sbill } 5462395Swnj out: 54713Sbill splx(s); 54813Sbill } 54913Sbill 55013Sbill /* 5512468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 55213Sbill */ 55313Sbill /*ARGSUSED*/ 55413Sbill dhstop(tp, flag) 5552468Swnj register struct tty *tp; 55613Sbill { 5572479Swnj register struct dhdevice *addr; 5582395Swnj register int unit, s; 55913Sbill 5602479Swnj addr = (struct dhdevice *)tp->t_addr; 5612468Swnj /* 5622468Swnj * Block input/output interrupts while messing with state. 5632468Swnj */ 5642468Swnj s = spl5(); 5655406Swnj if (tp->t_state & TS_BUSY) { 5662468Swnj /* 5672468Swnj * Device is transmitting; stop output 5682468Swnj * by selecting the line and setting the byte 5692468Swnj * count to -1. We will clean up later 5702468Swnj * by examining the address where the dh stopped. 5712468Swnj */ 5722395Swnj unit = minor(tp->t_dev); 5732456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5745406Swnj if ((tp->t_state&TS_TTSTOP)==0) 5755406Swnj tp->t_state |= TS_FLUSH; 576113Sbill addr->dhbcr = -1; 577113Sbill } 57813Sbill splx(s); 57913Sbill } 58013Sbill 581168Sbill /* 582280Sbill * Reset state of driver if UBA reset was necessary. 583280Sbill * Reset the csrl and lpr registers on open lines, and 584280Sbill * restart transmitters. 585280Sbill */ 5862395Swnj dhreset(uban) 5872468Swnj int uban; 588280Sbill { 5892395Swnj register int dh, unit; 590280Sbill register struct tty *tp; 5912974Swnj register struct uba_device *ui; 5922421Skre int i; 593280Sbill 5942421Skre if (dh_ubinfo[uban] == 0) 5952421Skre return; 5962421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 5972770Swnj 512+nclist*sizeof (struct cblock), 0); 5982421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 5992395Swnj dh = 0; 6002643Swnj for (dh = 0; dh < NDH; dh++) { 6012421Skre ui = dhinfo[dh]; 6022421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6032421Skre continue; 6042924Swnj printf(" dh%d", dh); 6052479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 60616190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; 6072421Skre unit = dh * 16; 6082421Skre for (i = 0; i < 16; i++) { 6092421Skre tp = &dh11[unit]; 6105406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6112421Skre dhparam(unit); 6122479Swnj dmctl(unit, DML_ON, DMSET); 6135406Swnj tp->t_state &= ~TS_BUSY; 6142421Skre dhstart(tp); 6152421Skre } 6162421Skre unit++; 617300Sbill } 618300Sbill } 61916190Skarels dhsilos = 0; 620280Sbill } 6212395Swnj 62216190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 6232468Swnj /* 62416190Skarels * At software clock interrupt time, check status. 62516190Skarels * Empty all the dh silos that are in use, and decide whether 62616190Skarels * to turn any silos off or on. 6272468Swnj */ 6282456Swnj dhtimer() 6292456Swnj { 63016190Skarels register int dh, s; 63116190Skarels static int timercalls; 6322456Swnj 63316190Skarels if (dhsilos) { 63416190Skarels dhfasttimers++; /*DEBUG*/ 63516190Skarels timercalls++; 63616190Skarels s = spl5(); 63716190Skarels for (dh = 0; dh < NDH; dh++) 63816190Skarels if (dhsilos & (1 << dh)) 63916190Skarels dhrint(dh); 64016190Skarels splx(s); 64116190Skarels } 64216190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 64316190Skarels dhslowtimers++; /*DEBUG*/ 64416190Skarels timercalls = 0; 64516190Skarels for (dh = 0; dh < NDH; dh++) { 64616190Skarels ave(dhrate[dh], dhchars[dh], 8); 64716190Skarels if ((dhchars[dh] > dhhighrate) && 64816190Skarels ((dhsilos & (1 << dh)) == 0)) { 64916190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 65016190Skarels (dhchars[dh] > 500? 32 : 16); 65116190Skarels dhsilos |= (1 << dh); 65216190Skarels dhtransitions++; /*DEBUG*/ 65316190Skarels } else if ((dhsilos & (1 << dh)) && 65416190Skarels (dhrate[dh] < dhlowrate)) { 65516190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; 65616190Skarels dhsilos &= ~(1 << dh); 65716190Skarels } 65816190Skarels dhchars[dh] = 0; 65916190Skarels } 66016190Skarels } 66116190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); 6622456Swnj } 6632456Swnj 6642468Swnj /* 6652479Swnj * Turn on the line associated with dh dev. 6662468Swnj */ 6672468Swnj dmopen(dev) 6682468Swnj dev_t dev; 6692468Swnj { 6702468Swnj register struct tty *tp; 6712468Swnj register struct dmdevice *addr; 6722974Swnj register struct uba_device *ui; 6732468Swnj register int unit; 6742468Swnj register int dm; 6753792Swnj int s; 6762468Swnj 6772468Swnj unit = minor(dev); 6782479Swnj dm = unit >> 4; 6792468Swnj tp = &dh11[unit]; 6802566Swnj unit &= 0xf; 68116942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 6825406Swnj tp->t_state |= TS_CARR_ON; 6832468Swnj return; 6842468Swnj } 6852468Swnj addr = (struct dmdevice *)ui->ui_addr; 6863792Swnj s = spl5(); 6872479Swnj addr->dmcsr &= ~DM_SE; 6882479Swnj while (addr->dmcsr & DM_BUSY) 6892468Swnj ; 6902566Swnj addr->dmcsr = unit; 6912479Swnj addr->dmlstat = DML_ON; 69216942Skarels if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit))) 6935406Swnj tp->t_state |= TS_CARR_ON; 6943792Swnj addr->dmcsr = DM_IE|DM_SE; 6955406Swnj while ((tp->t_state&TS_CARR_ON)==0) 6962468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6973792Swnj splx(s); 6982468Swnj } 6992468Swnj 7002468Swnj /* 7012468Swnj * Dump control bits into the DM registers. 7022468Swnj */ 7032468Swnj dmctl(dev, bits, how) 7042468Swnj dev_t dev; 7052468Swnj int bits, how; 7062468Swnj { 7072974Swnj register struct uba_device *ui; 7082468Swnj register struct dmdevice *addr; 7092468Swnj register int unit, s; 7102468Swnj int dm; 7112468Swnj 7122468Swnj unit = minor(dev); 7132468Swnj dm = unit >> 4; 7142468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7152468Swnj return; 7162468Swnj addr = (struct dmdevice *)ui->ui_addr; 7172468Swnj s = spl5(); 7182479Swnj addr->dmcsr &= ~DM_SE; 7192479Swnj while (addr->dmcsr & DM_BUSY) 7202468Swnj ; 7212468Swnj addr->dmcsr = unit & 0xf; 7222468Swnj switch(how) { 7232468Swnj case DMSET: 7242468Swnj addr->dmlstat = bits; 7252468Swnj break; 7262468Swnj case DMBIS: 7272468Swnj addr->dmlstat |= bits; 7282468Swnj break; 7292468Swnj case DMBIC: 7302468Swnj addr->dmlstat &= ~bits; 7312468Swnj break; 7322468Swnj } 7333792Swnj addr->dmcsr = DM_IE|DM_SE; 7342468Swnj splx(s); 7352468Swnj } 7362468Swnj 7372468Swnj /* 7382468Swnj * DM11 interrupt; deal with carrier transitions. 7392468Swnj */ 7402468Swnj dmintr(dm) 7412468Swnj register int dm; 7422468Swnj { 7432974Swnj register struct uba_device *ui; 7442468Swnj register struct tty *tp; 7452468Swnj register struct dmdevice *addr; 74616942Skarels int unit; 7472468Swnj 7482468Swnj ui = dminfo[dm]; 7492479Swnj if (ui == 0) 7502479Swnj return; 7512468Swnj addr = (struct dmdevice *)ui->ui_addr; 7523997Sroot if (addr->dmcsr&DM_DONE) { 7533997Sroot if (addr->dmcsr&DM_CF) { 75416942Skarels unit = addr->dmcsr & 0xf; 75516942Skarels tp = &dh11[(dm << 4) + unit]; 7563997Sroot wakeup((caddr_t)&tp->t_rawq); 7579549Ssam if ((tp->t_state&TS_WOPEN) == 0 && 7589605Ssam (tp->t_flags & MDMBUF)) { 7593997Sroot if (addr->dmlstat & DML_CAR) { 7605406Swnj tp->t_state &= ~TS_TTSTOP; 7613997Sroot ttstart(tp); 7625406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7635406Swnj tp->t_state |= TS_TTSTOP; 7643997Sroot dhstop(tp, 0); 7653997Sroot } 766*21954Skarels } else if ((addr->dmlstat & DML_CAR)==0) { 767*21954Skarels if ((tp->t_state & TS_CARR_ON) && 76816942Skarels (tp->t_flags & NOHANG) == 0 && 76916942Skarels (dhsoftCAR[dm] & (1<<unit)) == 0) { 770*21954Skarels if (tp->t_state & TS_ISOPEN) { 771*21954Skarels gsignal(tp->t_pgrp, SIGHUP); 772*21954Skarels gsignal(tp->t_pgrp, SIGCONT); 773*21954Skarels addr->dmlstat = 0; 774*21954Skarels ttyflush(tp, FREAD|FWRITE); 775*21954Skarels } 776*21954Skarels tp->t_state &= ~TS_CARR_ON; 7773997Sroot } 7783997Sroot } else 7795406Swnj tp->t_state |= TS_CARR_ON; 7803997Sroot } 7813997Sroot addr->dmcsr = DM_IE|DM_SE; 7822468Swnj } 7832468Swnj } 7842625Swnj #endif 785