1*16062Skarels /* dh.c 6.2 84/02/16 */ 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" 11*16062Skarels #include "uba.h" 1213Sbill #include "../h/param.h" 1313Sbill #include "../h/conf.h" 1413Sbill #include "../h/dir.h" 1513Sbill #include "../h/user.h" 166185Ssam #include "../h/proc.h" 179549Ssam #include "../h/ioctl.h" 1813Sbill #include "../h/tty.h" 1913Sbill #include "../h/map.h" 202395Swnj #include "../h/buf.h" 212566Swnj #include "../h/vm.h" 228472Sroot 238472Sroot #include "../vaxuba/ubareg.h" 248472Sroot #include "../vaxuba/ubavar.h" 2510018Ssam #include "../vaxuba/dhreg.h" 2610018Ssam #include "../vaxuba/dmreg.h" 278472Sroot 28113Sbill #include "../h/bk.h" 291561Sbill #include "../h/clist.h" 302468Swnj #include "../h/file.h" 317725Sroot #include "../h/uio.h" 3213Sbill 332468Swnj /* 342479Swnj * Definition of the driver for the auto-configuration program. 352479Swnj * There is one definition for the dh and one for the dm. 362468Swnj */ 372605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 382974Swnj struct uba_device *dhinfo[NDH]; 392395Swnj u_short dhstd[] = { 0 }; 402395Swnj struct uba_driver dhdriver = 412605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 422395Swnj 432605Swnj int dmprobe(), dmattach(), dmintr(); 442974Swnj struct uba_device *dminfo[NDH]; 452479Swnj u_short dmstd[] = { 0 }; 462479Swnj struct uba_driver dmdriver = 472605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4813Sbill 496615Ssam #ifndef PORTSELECTOR 506615Ssam #define ISPEED B300 516615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 526615Ssam #else 536615Ssam #define ISPEED B4800 546615Ssam #define IFLAGS (EVENP|ODDP) 556615Ssam #endif 566615Ssam 5713Sbill /* 582479Swnj * Local variables for the driver 5913Sbill */ 602643Swnj short dhsar[NDH]; /* software copy of last bar */ 612643Swnj short dhsoftCAR[NDH]; 6213Sbill 632643Swnj struct tty dh11[NDH*16]; 642643Swnj int ndh11 = NDH*16; 652479Swnj int dhact; /* mask of active dh's */ 662479Swnj int dhstart(), ttrstrt(); 6713Sbill 682479Swnj /* 692479Swnj * The clist space is mapped by the driver onto each UNIBUS. 702479Swnj * The UBACVT macro converts a clist space address for unibus uban 712479Swnj * into an i/o space address for the DMA routine. 722479Swnj */ 73*16062Skarels int dh_ubinfo[NUBA]; /* info about allocated unibus map */ 74*16062Skarels int cbase[NUBA]; /* base address in unibus map */ 752479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 7613Sbill 772456Swnj /* 782456Swnj * Routine for configuration to force a dh to interrupt. 792456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 802456Swnj */ 812468Swnj /*ARGSUSED*/ 822605Swnj dhprobe(reg) 832395Swnj caddr_t reg; 842395Swnj { 852468Swnj register int br, cvec; /* these are ``value-result'' */ 862479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 872395Swnj 882605Swnj #ifdef lint 892605Swnj br = 0; cvec = br; br = cvec; 907384Sroot if (ndh11 == 0) ndh11 = 1; 914932Swnj dhrint(0); dhxint(0); 922605Swnj #endif 932696Swnj #ifndef notdef 942566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 956380Swnj DELAY(1000); 967384Sroot dhaddr->un.dhcsr &= ~DH_RI; 972566Swnj dhaddr->un.dhcsr = 0; 982566Swnj #else 992456Swnj dhaddr->un.dhcsr = DH_TIE; 1002456Swnj DELAY(5); 1012456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1022421Skre dhaddr->dhbcr = -1; 1032456Swnj dhaddr->dhcar = 0; 1042421Skre dhaddr->dhbar = 1; 1052456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1062421Skre dhaddr->un.dhcsr = 0; 1072456Swnj if (cvec && cvec != 0x200) 1082456Swnj cvec -= 4; /* transmit -> receive */ 1092482Swnj #endif 1107408Skre return (sizeof (struct dhdevice)); 1112395Swnj } 1122395Swnj 1132456Swnj /* 1142605Swnj * Routine called to attach a dh. 1152456Swnj */ 1162605Swnj dhattach(ui) 1172974Swnj struct uba_device *ui; 1182395Swnj { 1192395Swnj 1202566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1212395Swnj } 1222395Swnj 12313Sbill /* 1242479Swnj * Configuration routine to cause a dm to interrupt. 1252479Swnj */ 1262605Swnj dmprobe(reg) 1272605Swnj caddr_t reg; 1282479Swnj { 1292479Swnj register int br, vec; /* value-result */ 1302605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1312479Swnj 1322605Swnj #ifdef lint 1333101Swnj br = 0; vec = br; br = vec; 1346185Ssam dmintr(0); 1352605Swnj #endif 1362479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1372479Swnj DELAY(20); 1382479Swnj dmaddr->dmcsr = 0; 1392605Swnj return (1); 1402479Swnj } 1412479Swnj 1422605Swnj /*ARGSUSED*/ 1432605Swnj dmattach(ui) 1442974Swnj struct uba_device *ui; 1452479Swnj { 1462479Swnj 1472479Swnj /* no local state to set up */ 1482479Swnj } 1492479Swnj 1502479Swnj /* 1512468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1522468Swnj * is the first dh on this uba. Turn on this dh if this is 1532468Swnj * the first use of it. Also do a dmopen to wait for carrier. 15413Sbill */ 15513Sbill /*ARGSUSED*/ 15613Sbill dhopen(dev, flag) 1572395Swnj dev_t dev; 15813Sbill { 15913Sbill register struct tty *tp; 1602395Swnj register int unit, dh; 1612479Swnj register struct dhdevice *addr; 1622974Swnj register struct uba_device *ui; 16313Sbill int s; 16413Sbill 1652395Swnj unit = minor(dev); 1662395Swnj dh = unit >> 4; 1678566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 1688566Sroot return (ENXIO); 1692395Swnj tp = &dh11[unit]; 1708566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1718566Sroot return (EBUSY); 1722479Swnj addr = (struct dhdevice *)ui->ui_addr; 17313Sbill tp->t_addr = (caddr_t)addr; 17413Sbill tp->t_oproc = dhstart; 1755406Swnj tp->t_state |= TS_WOPEN; 1762468Swnj /* 1772468Swnj * While setting up state for this uba and this dh, 1782468Swnj * block uba resets which can clear the state. 1792468Swnj */ 1802468Swnj s = spl5(); 1812421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 182717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1832395Swnj dh_ubinfo[ui->ui_ubanum] = 1842421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 1852770Swnj 512+nclist*sizeof(struct cblock), 0); 1862456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 18713Sbill } 1882456Swnj if ((dhact&(1<<dh)) == 0) { 1892456Swnj addr->un.dhcsr |= DH_IE; 1902468Swnj dhact |= (1<<dh); 1912456Swnj addr->dhsilo = 16; 1922456Swnj } 19313Sbill splx(s); 1942468Swnj /* 1952468Swnj * If this is first open, initialze tty state to default. 1962468Swnj */ 1975406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 19813Sbill ttychars(tp); 1996615Ssam #ifndef PORTSELECTOR 200168Sbill if (tp->t_ispeed == 0) { 2016615Ssam #endif 2026615Ssam tp->t_ispeed = ISPEED; 2036615Ssam tp->t_ospeed = ISPEED; 2046615Ssam tp->t_flags = IFLAGS; 2056615Ssam #ifndef PORTSELECTOR 206168Sbill } 2076615Ssam #endif 2082395Swnj dhparam(unit); 20913Sbill } 2102468Swnj /* 2112468Swnj * Wait for carrier, then process line discipline specific open. 2122468Swnj */ 21313Sbill dmopen(dev); 2148566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 21513Sbill } 21613Sbill 21713Sbill /* 2182468Swnj * Close a DH11 line, turning off the DM11. 21913Sbill */ 22013Sbill /*ARGSUSED*/ 22113Sbill dhclose(dev, flag) 2222395Swnj dev_t dev; 2232395Swnj int flag; 22413Sbill { 22513Sbill register struct tty *tp; 2262395Swnj register unit; 22713Sbill 2282395Swnj unit = minor(dev); 2292395Swnj tp = &dh11[unit]; 23013Sbill (*linesw[tp->t_line].l_close)(tp); 2312479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2325406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2332479Swnj dmctl(unit, DML_OFF, DMSET); 23413Sbill ttyclose(tp); 23513Sbill } 23613Sbill 2377725Sroot dhread(dev, uio) 2382395Swnj dev_t dev; 2397725Sroot struct uio *uio; 24013Sbill { 2418490Sroot register struct tty *tp = &dh11[minor(dev)]; 24213Sbill 2437725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 24413Sbill } 24513Sbill 2467831Sroot dhwrite(dev, uio) 2472395Swnj dev_t dev; 2487831Sroot struct uio *uio; 24913Sbill { 2508490Sroot register struct tty *tp = &dh11[minor(dev)]; 25113Sbill 2528490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 25313Sbill } 25413Sbill 25513Sbill /* 25613Sbill * DH11 receiver interrupt. 25713Sbill */ 2582395Swnj dhrint(dh) 2592395Swnj int dh; 26013Sbill { 26113Sbill register struct tty *tp; 2622395Swnj register c; 2632479Swnj register struct dhdevice *addr; 264117Sbill register struct tty *tp0; 2652974Swnj register struct uba_device *ui; 2662924Swnj int overrun = 0; 26713Sbill 2682395Swnj ui = dhinfo[dh]; 2692479Swnj if (ui == 0 || ui->ui_alive == 0) 2702479Swnj return; 2712479Swnj addr = (struct dhdevice *)ui->ui_addr; 2722468Swnj tp0 = &dh11[dh<<4]; 2732468Swnj /* 2742468Swnj * Loop fetching characters from the silo for this 2752468Swnj * dh until there are no more in the silo. 2762468Swnj */ 2772468Swnj while ((c = addr->dhrcr) < 0) { 2782468Swnj tp = tp0 + ((c>>8)&0xf); 2796615Ssam #ifndef PORTSELECTOR 2805406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 2816615Ssam #else 2826615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 2836615Ssam #endif 28413Sbill wakeup((caddr_t)tp); 28513Sbill continue; 28613Sbill } 2872468Swnj if (c & DH_PE) 28813Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 28913Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 29013Sbill continue; 2912924Swnj if ((c & DH_DO) && overrun == 0) { 2922924Swnj printf("dh%d: silo overflow\n", dh); 2932924Swnj overrun = 1; 2942924Swnj } 2952468Swnj if (c & DH_FE) 2962468Swnj /* 2972468Swnj * At framing error (break) generate 2982468Swnj * a null (in raw mode, for getty), or a 2992468Swnj * interrupt (in cooked/cbreak mode). 3002468Swnj */ 30113Sbill if (tp->t_flags&RAW) 3022468Swnj c = 0; 30313Sbill else 3049549Ssam c = tp->t_intrc; 3052730Swnj #if NBK > 0 306139Sbill if (tp->t_line == NETLDISC) { 307117Sbill c &= 0177; 308168Sbill BKINPUT(c, tp); 309117Sbill } else 3102730Swnj #endif 3112468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 31213Sbill } 31313Sbill } 31413Sbill 31513Sbill /* 3162468Swnj * Ioctl for DH11. 31713Sbill */ 31813Sbill /*ARGSUSED*/ 3197629Ssam dhioctl(dev, cmd, data, flag) 3207629Ssam caddr_t data; 32113Sbill { 32213Sbill register struct tty *tp; 3238566Sroot register int unit = minor(dev); 3248566Sroot int error; 32513Sbill 3262395Swnj tp = &dh11[unit]; 3278566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3288566Sroot if (error >= 0) 3298566Sroot return (error); 3308566Sroot error = ttioctl(tp, cmd, data, flag); 3318566Sroot if (error >= 0) { 3327629Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 3332395Swnj dhparam(unit); 3348566Sroot return (error); 3358566Sroot } 3368566Sroot switch (cmd) { 3377629Ssam 338168Sbill case TIOCSBRK: 3392479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 340168Sbill break; 3417629Ssam 342168Sbill case TIOCCBRK: 3432479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 344168Sbill break; 3457629Ssam 346168Sbill case TIOCSDTR: 3472479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 348168Sbill break; 3497629Ssam 350168Sbill case TIOCCDTR: 3512479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 352168Sbill break; 3537629Ssam 354168Sbill default: 3558566Sroot return (ENOTTY); 356168Sbill } 3578566Sroot return (0); 35813Sbill } 35913Sbill 36013Sbill /* 36113Sbill * Set parameters from open or stty into the DH hardware 36213Sbill * registers. 36313Sbill */ 3642395Swnj dhparam(unit) 3652395Swnj register int unit; 36613Sbill { 36713Sbill register struct tty *tp; 3682479Swnj register struct dhdevice *addr; 3692395Swnj register int lpar; 370300Sbill int s; 37113Sbill 3722395Swnj tp = &dh11[unit]; 3732479Swnj addr = (struct dhdevice *)tp->t_addr; 3742468Swnj /* 3752468Swnj * Block interrupts so parameters will be set 3762468Swnj * before the line interrupts. 3772468Swnj */ 378300Sbill s = spl5(); 3792468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 38013Sbill if ((tp->t_ispeed)==0) { 3815406Swnj tp->t_state |= TS_HUPCLS; 3822479Swnj dmctl(unit, DML_OFF, DMSET); 38313Sbill return; 38413Sbill } 3852395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 3862468Swnj if ((tp->t_ispeed) == B134) 3872395Swnj lpar |= BITS6|PENABLE|HDUPLX; 3889549Ssam else if (tp->t_flags & (RAW|LITOUT)) 3892395Swnj lpar |= BITS8; 39013Sbill else 3912395Swnj lpar |= BITS7|PENABLE; 39213Sbill if ((tp->t_flags&EVENP) == 0) 3932395Swnj lpar |= OPAR; 3942468Swnj if ((tp->t_ospeed) == B110) 3952395Swnj lpar |= TWOSB; 3962395Swnj addr->dhlpr = lpar; 397300Sbill splx(s); 39813Sbill } 39913Sbill 40013Sbill /* 40113Sbill * DH11 transmitter interrupt. 40213Sbill * Restart each line which used to be active but has 40313Sbill * terminated transmission since the last interrupt. 40413Sbill */ 4052395Swnj dhxint(dh) 4062395Swnj int dh; 40713Sbill { 40813Sbill register struct tty *tp; 4092479Swnj register struct dhdevice *addr; 41013Sbill short ttybit, bar, *sbar; 4112974Swnj register struct uba_device *ui; 4122468Swnj register int unit; 4132605Swnj u_short cntr; 41413Sbill 4152395Swnj ui = dhinfo[dh]; 4162479Swnj addr = (struct dhdevice *)ui->ui_addr; 4172456Swnj if (addr->un.dhcsr & DH_NXM) { 4182456Swnj addr->un.dhcsr |= DH_CNI; 4192924Swnj printf("dh%d: NXM\n", dh); 420105Sbill } 4212395Swnj sbar = &dhsar[dh]; 42213Sbill bar = *sbar & ~addr->dhbar; 4232395Swnj unit = dh * 16; ttybit = 1; 4242468Swnj addr->un.dhcsr &= (short)~DH_TI; 4252468Swnj for (; bar; unit++, ttybit <<= 1) { 4262468Swnj if (bar & ttybit) { 42713Sbill *sbar &= ~ttybit; 42813Sbill bar &= ~ttybit; 4292395Swnj tp = &dh11[unit]; 4305406Swnj tp->t_state &= ~TS_BUSY; 4315406Swnj if (tp->t_state&TS_FLUSH) 4325406Swnj tp->t_state &= ~TS_FLUSH; 433113Sbill else { 4342456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4352468Swnj /* 4362468Swnj * Do arithmetic in a short to make up 4372468Swnj * for lost 16&17 bits. 4382468Swnj */ 4392605Swnj cntr = addr->dhcar - 4402468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4413101Swnj ndflush(&tp->t_outq, (int)cntr); 442113Sbill } 443113Sbill if (tp->t_line) 44413Sbill (*linesw[tp->t_line].l_start)(tp); 445113Sbill else 44613Sbill dhstart(tp); 44713Sbill } 44813Sbill } 44913Sbill } 45013Sbill 45113Sbill /* 45213Sbill * Start (restart) transmission on the given DH11 line. 45313Sbill */ 45413Sbill dhstart(tp) 4552395Swnj register struct tty *tp; 45613Sbill { 4572479Swnj register struct dhdevice *addr; 4582468Swnj register int car, dh, unit, nch; 4592395Swnj int s; 46013Sbill 4612468Swnj unit = minor(tp->t_dev); 4622468Swnj dh = unit >> 4; 4632468Swnj unit &= 0xf; 4642479Swnj addr = (struct dhdevice *)tp->t_addr; 4652468Swnj 46613Sbill /* 4672468Swnj * Must hold interrupts in following code to prevent 4682468Swnj * state of the tp from changing. 46913Sbill */ 47013Sbill s = spl5(); 4712468Swnj /* 4722468Swnj * If it's currently active, or delaying, no need to do anything. 4732468Swnj */ 4745406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 47513Sbill goto out; 4762468Swnj /* 4772468Swnj * If there are sleepers, and output has drained below low 4782468Swnj * water mark, wake up the sleepers. 4792468Swnj */ 4805406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 4815406Swnj if (tp->t_state&TS_ASLEEP) { 4825406Swnj tp->t_state &= ~TS_ASLEEP; 4835406Swnj wakeup((caddr_t)&tp->t_outq); 4845406Swnj } 4855406Swnj if (tp->t_wsel) { 4865406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 4875406Swnj tp->t_wsel = 0; 4885406Swnj tp->t_state &= ~TS_WCOLL; 4895406Swnj } 49013Sbill } 4912468Swnj /* 4922468Swnj * Now restart transmission unless the output queue is 4932468Swnj * empty. 4942468Swnj */ 49513Sbill if (tp->t_outq.c_cc == 0) 49613Sbill goto out; 4979549Ssam if (tp->t_flags & (RAW|LITOUT)) 49813Sbill nch = ndqb(&tp->t_outq, 0); 4992395Swnj else { 50013Sbill nch = ndqb(&tp->t_outq, 0200); 5012468Swnj /* 5022468Swnj * If first thing on queue is a delay process it. 5032468Swnj */ 50413Sbill if (nch == 0) { 50513Sbill nch = getc(&tp->t_outq); 5062468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5075406Swnj tp->t_state |= TS_TIMEOUT; 50813Sbill goto out; 50913Sbill } 51013Sbill } 5112468Swnj /* 5122468Swnj * If characters to transmit, restart transmission. 5132468Swnj */ 51413Sbill if (nch) { 5152468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5162468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5173586Sroot /* 5183586Sroot * The following nonsense with short word 5193586Sroot * is to make sure the dhbar |= word below 5203586Sroot * is done with an interlocking bisw2 instruction. 5213586Sroot */ 5223586Sroot { short word = 1 << unit; 5233586Sroot dhsar[dh] |= word; 5242468Swnj addr->dhcar = car; 52513Sbill addr->dhbcr = -nch; 5263586Sroot addr->dhbar |= word; 5273586Sroot } 5285406Swnj tp->t_state |= TS_BUSY; 52913Sbill } 5302395Swnj out: 53113Sbill splx(s); 53213Sbill } 53313Sbill 53413Sbill /* 5352468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 53613Sbill */ 53713Sbill /*ARGSUSED*/ 53813Sbill dhstop(tp, flag) 5392468Swnj register struct tty *tp; 54013Sbill { 5412479Swnj register struct dhdevice *addr; 5422395Swnj register int unit, s; 54313Sbill 5442479Swnj addr = (struct dhdevice *)tp->t_addr; 5452468Swnj /* 5462468Swnj * Block input/output interrupts while messing with state. 5472468Swnj */ 5482468Swnj s = spl5(); 5495406Swnj if (tp->t_state & TS_BUSY) { 5502468Swnj /* 5512468Swnj * Device is transmitting; stop output 5522468Swnj * by selecting the line and setting the byte 5532468Swnj * count to -1. We will clean up later 5542468Swnj * by examining the address where the dh stopped. 5552468Swnj */ 5562395Swnj unit = minor(tp->t_dev); 5572456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5585406Swnj if ((tp->t_state&TS_TTSTOP)==0) 5595406Swnj tp->t_state |= TS_FLUSH; 560113Sbill addr->dhbcr = -1; 561113Sbill } 56213Sbill splx(s); 56313Sbill } 56413Sbill 565168Sbill /* 566280Sbill * Reset state of driver if UBA reset was necessary. 567280Sbill * Reset the csrl and lpr registers on open lines, and 568280Sbill * restart transmitters. 569280Sbill */ 5702395Swnj dhreset(uban) 5712468Swnj int uban; 572280Sbill { 5732395Swnj register int dh, unit; 574280Sbill register struct tty *tp; 5752974Swnj register struct uba_device *ui; 5762421Skre int i; 577280Sbill 5782421Skre if (dh_ubinfo[uban] == 0) 5792421Skre return; 5802421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 5812770Swnj 512+nclist*sizeof (struct cblock), 0); 5822421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 5832395Swnj dh = 0; 5842643Swnj for (dh = 0; dh < NDH; dh++) { 5852421Skre ui = dhinfo[dh]; 5862421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 5872421Skre continue; 5882924Swnj printf(" dh%d", dh); 5892479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 5902479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 5912421Skre unit = dh * 16; 5922421Skre for (i = 0; i < 16; i++) { 5932421Skre tp = &dh11[unit]; 5945406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 5952421Skre dhparam(unit); 5962479Swnj dmctl(unit, DML_ON, DMSET); 5975406Swnj tp->t_state &= ~TS_BUSY; 5982421Skre dhstart(tp); 5992421Skre } 6002421Skre unit++; 601300Sbill } 602300Sbill } 603300Sbill dhtimer(); 604280Sbill } 6052395Swnj 6062468Swnj /* 6072468Swnj * At software clock interrupt time or after a UNIBUS reset 6082468Swnj * empty all the dh silos. 6092468Swnj */ 6102456Swnj dhtimer() 6112456Swnj { 6122456Swnj register int dh; 6138159Sroot register int s = spl5(); 6142456Swnj 6152643Swnj for (dh = 0; dh < NDH; dh++) 6162456Swnj dhrint(dh); 6178159Sroot splx(s); 6182456Swnj } 6192456Swnj 6202468Swnj /* 6212479Swnj * Turn on the line associated with dh dev. 6222468Swnj */ 6232468Swnj dmopen(dev) 6242468Swnj dev_t dev; 6252468Swnj { 6262468Swnj register struct tty *tp; 6272468Swnj register struct dmdevice *addr; 6282974Swnj register struct uba_device *ui; 6292468Swnj register int unit; 6302468Swnj register int dm; 6313792Swnj int s; 6322468Swnj 6332468Swnj unit = minor(dev); 6342479Swnj dm = unit >> 4; 6352468Swnj tp = &dh11[unit]; 6362566Swnj unit &= 0xf; 6372643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 6382566Swnj (dhsoftCAR[dm]&(1<<unit))) { 6395406Swnj tp->t_state |= TS_CARR_ON; 6402468Swnj return; 6412468Swnj } 6422468Swnj addr = (struct dmdevice *)ui->ui_addr; 6433792Swnj s = spl5(); 6442479Swnj addr->dmcsr &= ~DM_SE; 6452479Swnj while (addr->dmcsr & DM_BUSY) 6462468Swnj ; 6472566Swnj addr->dmcsr = unit; 6482479Swnj addr->dmlstat = DML_ON; 6492479Swnj if (addr->dmlstat&DML_CAR) 6505406Swnj tp->t_state |= TS_CARR_ON; 6513792Swnj addr->dmcsr = DM_IE|DM_SE; 6525406Swnj while ((tp->t_state&TS_CARR_ON)==0) 6532468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6543792Swnj splx(s); 6552468Swnj } 6562468Swnj 6572468Swnj /* 6582468Swnj * Dump control bits into the DM registers. 6592468Swnj */ 6602468Swnj dmctl(dev, bits, how) 6612468Swnj dev_t dev; 6622468Swnj int bits, how; 6632468Swnj { 6642974Swnj register struct uba_device *ui; 6652468Swnj register struct dmdevice *addr; 6662468Swnj register int unit, s; 6672468Swnj int dm; 6682468Swnj 6692468Swnj unit = minor(dev); 6702468Swnj dm = unit >> 4; 6712468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 6722468Swnj return; 6732468Swnj addr = (struct dmdevice *)ui->ui_addr; 6742468Swnj s = spl5(); 6752479Swnj addr->dmcsr &= ~DM_SE; 6762479Swnj while (addr->dmcsr & DM_BUSY) 6772468Swnj ; 6782468Swnj addr->dmcsr = unit & 0xf; 6792468Swnj switch(how) { 6802468Swnj case DMSET: 6812468Swnj addr->dmlstat = bits; 6822468Swnj break; 6832468Swnj case DMBIS: 6842468Swnj addr->dmlstat |= bits; 6852468Swnj break; 6862468Swnj case DMBIC: 6872468Swnj addr->dmlstat &= ~bits; 6882468Swnj break; 6892468Swnj } 6903792Swnj addr->dmcsr = DM_IE|DM_SE; 6912468Swnj splx(s); 6922468Swnj } 6932468Swnj 6942468Swnj /* 6952468Swnj * DM11 interrupt; deal with carrier transitions. 6962468Swnj */ 6972468Swnj dmintr(dm) 6982468Swnj register int dm; 6992468Swnj { 7002974Swnj register struct uba_device *ui; 7012468Swnj register struct tty *tp; 7022468Swnj register struct dmdevice *addr; 7032468Swnj 7042468Swnj ui = dminfo[dm]; 7052479Swnj if (ui == 0) 7062479Swnj return; 7072468Swnj addr = (struct dmdevice *)ui->ui_addr; 7083997Sroot if (addr->dmcsr&DM_DONE) { 7093997Sroot if (addr->dmcsr&DM_CF) { 7103997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7113997Sroot wakeup((caddr_t)&tp->t_rawq); 7129549Ssam if ((tp->t_state&TS_WOPEN) == 0 && 7139605Ssam (tp->t_flags & MDMBUF)) { 7143997Sroot if (addr->dmlstat & DML_CAR) { 7155406Swnj tp->t_state &= ~TS_TTSTOP; 7163997Sroot ttstart(tp); 7175406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7185406Swnj tp->t_state |= TS_TTSTOP; 7193997Sroot dhstop(tp, 0); 7203997Sroot } 7213997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7225406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7239605Ssam (tp->t_flags & NOHANG) == 0) { 7243997Sroot gsignal(tp->t_pgrp, SIGHUP); 7253997Sroot gsignal(tp->t_pgrp, SIGCONT); 7263997Sroot addr->dmlstat = 0; 72712775Ssam ttyflush(tp, FREAD|FWRITE); 7283997Sroot } 7295406Swnj tp->t_state &= ~TS_CARR_ON; 7303997Sroot } else 7315406Swnj tp->t_state |= TS_CARR_ON; 7323997Sroot } 7333997Sroot addr->dmcsr = DM_IE|DM_SE; 7342468Swnj } 7352468Swnj } 7362625Swnj #endif 737