1*10018Ssam /* dh.c 4.57 82/12/30 */ 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" 1113Sbill #include "../h/param.h" 1213Sbill #include "../h/conf.h" 1313Sbill #include "../h/dir.h" 1413Sbill #include "../h/user.h" 156185Ssam #include "../h/proc.h" 169549Ssam #include "../h/ioctl.h" 1713Sbill #include "../h/tty.h" 1813Sbill #include "../h/map.h" 192395Swnj #include "../h/buf.h" 202566Swnj #include "../h/vm.h" 218472Sroot 228472Sroot #include "../vaxuba/ubareg.h" 238472Sroot #include "../vaxuba/ubavar.h" 24*10018Ssam #include "../vaxuba/dhreg.h" 25*10018Ssam #include "../vaxuba/dmreg.h" 268472Sroot 27113Sbill #include "../h/bk.h" 281561Sbill #include "../h/clist.h" 292468Swnj #include "../h/file.h" 307725Sroot #include "../h/uio.h" 3113Sbill 322468Swnj /* 332479Swnj * Definition of the driver for the auto-configuration program. 342479Swnj * There is one definition for the dh and one for the dm. 352468Swnj */ 362605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 372974Swnj struct uba_device *dhinfo[NDH]; 382395Swnj u_short dhstd[] = { 0 }; 392395Swnj struct uba_driver dhdriver = 402605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 412395Swnj 422605Swnj int dmprobe(), dmattach(), dmintr(); 432974Swnj struct uba_device *dminfo[NDH]; 442479Swnj u_short dmstd[] = { 0 }; 452479Swnj struct uba_driver dmdriver = 462605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4713Sbill 486615Ssam #ifndef PORTSELECTOR 496615Ssam #define ISPEED B300 506615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 516615Ssam #else 526615Ssam #define ISPEED B4800 536615Ssam #define IFLAGS (EVENP|ODDP) 546615Ssam #endif 556615Ssam 5613Sbill /* 572479Swnj * Local variables for the driver 5813Sbill */ 592643Swnj short dhsar[NDH]; /* software copy of last bar */ 602643Swnj short dhsoftCAR[NDH]; 6113Sbill 622643Swnj struct tty dh11[NDH*16]; 632643Swnj int ndh11 = NDH*16; 642479Swnj int dhact; /* mask of active dh's */ 652479Swnj int dhstart(), ttrstrt(); 6613Sbill 672479Swnj /* 682479Swnj * The clist space is mapped by the driver onto each UNIBUS. 692479Swnj * The UBACVT macro converts a clist space address for unibus uban 702479Swnj * into an i/o space address for the DMA routine. 712479Swnj */ 722479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 732479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 742479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 7513Sbill 762456Swnj /* 772456Swnj * Routine for configuration to force a dh to interrupt. 782456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 792456Swnj */ 802468Swnj /*ARGSUSED*/ 812605Swnj dhprobe(reg) 822395Swnj caddr_t reg; 832395Swnj { 842468Swnj register int br, cvec; /* these are ``value-result'' */ 852479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 862395Swnj 872605Swnj #ifdef lint 882605Swnj br = 0; cvec = br; br = cvec; 897384Sroot if (ndh11 == 0) ndh11 = 1; 904932Swnj dhrint(0); dhxint(0); 912605Swnj #endif 922696Swnj #ifndef notdef 932566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 946380Swnj DELAY(1000); 957384Sroot dhaddr->un.dhcsr &= ~DH_RI; 962566Swnj dhaddr->un.dhcsr = 0; 972566Swnj #else 982456Swnj dhaddr->un.dhcsr = DH_TIE; 992456Swnj DELAY(5); 1002456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1012421Skre dhaddr->dhbcr = -1; 1022456Swnj dhaddr->dhcar = 0; 1032421Skre dhaddr->dhbar = 1; 1042456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1052421Skre dhaddr->un.dhcsr = 0; 1062456Swnj if (cvec && cvec != 0x200) 1072456Swnj cvec -= 4; /* transmit -> receive */ 1082482Swnj #endif 1097408Skre return (sizeof (struct dhdevice)); 1102395Swnj } 1112395Swnj 1122456Swnj /* 1132605Swnj * Routine called to attach a dh. 1142456Swnj */ 1152605Swnj dhattach(ui) 1162974Swnj struct uba_device *ui; 1172395Swnj { 1182395Swnj 1192566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1202395Swnj } 1212395Swnj 12213Sbill /* 1232479Swnj * Configuration routine to cause a dm to interrupt. 1242479Swnj */ 1252605Swnj dmprobe(reg) 1262605Swnj caddr_t reg; 1272479Swnj { 1282479Swnj register int br, vec; /* value-result */ 1292605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1302479Swnj 1312605Swnj #ifdef lint 1323101Swnj br = 0; vec = br; br = vec; 1336185Ssam dmintr(0); 1342605Swnj #endif 1352479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1362479Swnj DELAY(20); 1372479Swnj dmaddr->dmcsr = 0; 1382605Swnj return (1); 1392479Swnj } 1402479Swnj 1412605Swnj /*ARGSUSED*/ 1422605Swnj dmattach(ui) 1432974Swnj struct uba_device *ui; 1442479Swnj { 1452479Swnj 1462479Swnj /* no local state to set up */ 1472479Swnj } 1482479Swnj 1492479Swnj /* 1502468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1512468Swnj * is the first dh on this uba. Turn on this dh if this is 1522468Swnj * the first use of it. Also do a dmopen to wait for carrier. 15313Sbill */ 15413Sbill /*ARGSUSED*/ 15513Sbill dhopen(dev, flag) 1562395Swnj dev_t dev; 15713Sbill { 15813Sbill register struct tty *tp; 1592395Swnj register int unit, dh; 1602479Swnj register struct dhdevice *addr; 1612974Swnj register struct uba_device *ui; 16213Sbill int s; 16313Sbill 1642395Swnj unit = minor(dev); 1652395Swnj dh = unit >> 4; 1668566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 1678566Sroot return (ENXIO); 1682395Swnj tp = &dh11[unit]; 1698566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1708566Sroot return (EBUSY); 1712479Swnj addr = (struct dhdevice *)ui->ui_addr; 17213Sbill tp->t_addr = (caddr_t)addr; 17313Sbill tp->t_oproc = dhstart; 1745406Swnj tp->t_state |= TS_WOPEN; 1752468Swnj /* 1762468Swnj * While setting up state for this uba and this dh, 1772468Swnj * block uba resets which can clear the state. 1782468Swnj */ 1792468Swnj s = spl5(); 1802421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 181717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1822395Swnj dh_ubinfo[ui->ui_ubanum] = 1832421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 1842770Swnj 512+nclist*sizeof(struct cblock), 0); 1852456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 18613Sbill } 1872456Swnj if ((dhact&(1<<dh)) == 0) { 1882456Swnj addr->un.dhcsr |= DH_IE; 1892468Swnj dhact |= (1<<dh); 1902456Swnj addr->dhsilo = 16; 1912456Swnj } 19213Sbill splx(s); 1932468Swnj /* 1942468Swnj * If this is first open, initialze tty state to default. 1952468Swnj */ 1965406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 19713Sbill ttychars(tp); 1986615Ssam #ifndef PORTSELECTOR 199168Sbill if (tp->t_ispeed == 0) { 2006615Ssam #endif 2016615Ssam tp->t_ispeed = ISPEED; 2026615Ssam tp->t_ospeed = ISPEED; 2036615Ssam tp->t_flags = IFLAGS; 2046615Ssam #ifndef PORTSELECTOR 205168Sbill } 2066615Ssam #endif 2072395Swnj dhparam(unit); 20813Sbill } 2092468Swnj /* 2102468Swnj * Wait for carrier, then process line discipline specific open. 2112468Swnj */ 21213Sbill dmopen(dev); 2138566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 21413Sbill } 21513Sbill 21613Sbill /* 2172468Swnj * Close a DH11 line, turning off the DM11. 21813Sbill */ 21913Sbill /*ARGSUSED*/ 22013Sbill dhclose(dev, flag) 2212395Swnj dev_t dev; 2222395Swnj int flag; 22313Sbill { 22413Sbill register struct tty *tp; 2252395Swnj register unit; 22613Sbill 2272395Swnj unit = minor(dev); 2282395Swnj tp = &dh11[unit]; 22913Sbill (*linesw[tp->t_line].l_close)(tp); 2302479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2315406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2322479Swnj dmctl(unit, DML_OFF, DMSET); 23313Sbill ttyclose(tp); 23413Sbill } 23513Sbill 2367725Sroot dhread(dev, uio) 2372395Swnj dev_t dev; 2387725Sroot struct uio *uio; 23913Sbill { 2408490Sroot register struct tty *tp = &dh11[minor(dev)]; 24113Sbill 2427725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 24313Sbill } 24413Sbill 2457831Sroot dhwrite(dev, uio) 2462395Swnj dev_t dev; 2477831Sroot struct uio *uio; 24813Sbill { 2498490Sroot register struct tty *tp = &dh11[minor(dev)]; 25013Sbill 2518490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 25213Sbill } 25313Sbill 25413Sbill /* 25513Sbill * DH11 receiver interrupt. 25613Sbill */ 2572395Swnj dhrint(dh) 2582395Swnj int dh; 25913Sbill { 26013Sbill register struct tty *tp; 2612395Swnj register c; 2622479Swnj register struct dhdevice *addr; 263117Sbill register struct tty *tp0; 2642974Swnj register struct uba_device *ui; 2652924Swnj int overrun = 0; 26613Sbill 2672395Swnj ui = dhinfo[dh]; 2682479Swnj if (ui == 0 || ui->ui_alive == 0) 2692479Swnj return; 2702479Swnj addr = (struct dhdevice *)ui->ui_addr; 2712468Swnj tp0 = &dh11[dh<<4]; 2722468Swnj /* 2732468Swnj * Loop fetching characters from the silo for this 2742468Swnj * dh until there are no more in the silo. 2752468Swnj */ 2762468Swnj while ((c = addr->dhrcr) < 0) { 2772468Swnj tp = tp0 + ((c>>8)&0xf); 2786615Ssam #ifndef PORTSELECTOR 2795406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 2806615Ssam #else 2816615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 2826615Ssam #endif 28313Sbill wakeup((caddr_t)tp); 28413Sbill continue; 28513Sbill } 2862468Swnj if (c & DH_PE) 28713Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 28813Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 28913Sbill continue; 2902924Swnj if ((c & DH_DO) && overrun == 0) { 2912924Swnj printf("dh%d: silo overflow\n", dh); 2922924Swnj overrun = 1; 2932924Swnj } 2942468Swnj if (c & DH_FE) 2952468Swnj /* 2962468Swnj * At framing error (break) generate 2972468Swnj * a null (in raw mode, for getty), or a 2982468Swnj * interrupt (in cooked/cbreak mode). 2992468Swnj */ 30013Sbill if (tp->t_flags&RAW) 3012468Swnj c = 0; 30213Sbill else 3039549Ssam c = tp->t_intrc; 3042730Swnj #if NBK > 0 305139Sbill if (tp->t_line == NETLDISC) { 306117Sbill c &= 0177; 307168Sbill BKINPUT(c, tp); 308117Sbill } else 3092730Swnj #endif 3102468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 31113Sbill } 31213Sbill } 31313Sbill 31413Sbill /* 3152468Swnj * Ioctl for DH11. 31613Sbill */ 31713Sbill /*ARGSUSED*/ 3187629Ssam dhioctl(dev, cmd, data, flag) 3197629Ssam caddr_t data; 32013Sbill { 32113Sbill register struct tty *tp; 3228566Sroot register int unit = minor(dev); 3238566Sroot int error; 32413Sbill 3252395Swnj tp = &dh11[unit]; 3268566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3278566Sroot if (error >= 0) 3288566Sroot return (error); 3298566Sroot error = ttioctl(tp, cmd, data, flag); 3308566Sroot if (error >= 0) { 3317629Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 3322395Swnj dhparam(unit); 3338566Sroot return (error); 3348566Sroot } 3358566Sroot switch (cmd) { 3367629Ssam 337168Sbill case TIOCSBRK: 3382479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 339168Sbill break; 3407629Ssam 341168Sbill case TIOCCBRK: 3422479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 343168Sbill break; 3447629Ssam 345168Sbill case TIOCSDTR: 3462479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 347168Sbill break; 3487629Ssam 349168Sbill case TIOCCDTR: 3502479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 351168Sbill break; 3527629Ssam 353168Sbill default: 3548566Sroot return (ENOTTY); 355168Sbill } 3568566Sroot return (0); 35713Sbill } 35813Sbill 35913Sbill /* 36013Sbill * Set parameters from open or stty into the DH hardware 36113Sbill * registers. 36213Sbill */ 3632395Swnj dhparam(unit) 3642395Swnj register int unit; 36513Sbill { 36613Sbill register struct tty *tp; 3672479Swnj register struct dhdevice *addr; 3682395Swnj register int lpar; 369300Sbill int s; 37013Sbill 3712395Swnj tp = &dh11[unit]; 3722479Swnj addr = (struct dhdevice *)tp->t_addr; 3732468Swnj /* 3742468Swnj * Block interrupts so parameters will be set 3752468Swnj * before the line interrupts. 3762468Swnj */ 377300Sbill s = spl5(); 3782468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 37913Sbill if ((tp->t_ispeed)==0) { 3805406Swnj tp->t_state |= TS_HUPCLS; 3812479Swnj dmctl(unit, DML_OFF, DMSET); 38213Sbill return; 38313Sbill } 3842395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 3852468Swnj if ((tp->t_ispeed) == B134) 3862395Swnj lpar |= BITS6|PENABLE|HDUPLX; 3879549Ssam else if (tp->t_flags & (RAW|LITOUT)) 3882395Swnj lpar |= BITS8; 38913Sbill else 3902395Swnj lpar |= BITS7|PENABLE; 39113Sbill if ((tp->t_flags&EVENP) == 0) 3922395Swnj lpar |= OPAR; 3932468Swnj if ((tp->t_ospeed) == B110) 3942395Swnj lpar |= TWOSB; 3952395Swnj addr->dhlpr = lpar; 396300Sbill splx(s); 39713Sbill } 39813Sbill 39913Sbill /* 40013Sbill * DH11 transmitter interrupt. 40113Sbill * Restart each line which used to be active but has 40213Sbill * terminated transmission since the last interrupt. 40313Sbill */ 4042395Swnj dhxint(dh) 4052395Swnj int dh; 40613Sbill { 40713Sbill register struct tty *tp; 4082479Swnj register struct dhdevice *addr; 40913Sbill short ttybit, bar, *sbar; 4102974Swnj register struct uba_device *ui; 4112468Swnj register int unit; 4122605Swnj u_short cntr; 41313Sbill 4142395Swnj ui = dhinfo[dh]; 4152479Swnj addr = (struct dhdevice *)ui->ui_addr; 4162456Swnj if (addr->un.dhcsr & DH_NXM) { 4172456Swnj addr->un.dhcsr |= DH_CNI; 4182924Swnj printf("dh%d: NXM\n", dh); 419105Sbill } 4202395Swnj sbar = &dhsar[dh]; 42113Sbill bar = *sbar & ~addr->dhbar; 4222395Swnj unit = dh * 16; ttybit = 1; 4232468Swnj addr->un.dhcsr &= (short)~DH_TI; 4242468Swnj for (; bar; unit++, ttybit <<= 1) { 4252468Swnj if (bar & ttybit) { 42613Sbill *sbar &= ~ttybit; 42713Sbill bar &= ~ttybit; 4282395Swnj tp = &dh11[unit]; 4295406Swnj tp->t_state &= ~TS_BUSY; 4305406Swnj if (tp->t_state&TS_FLUSH) 4315406Swnj tp->t_state &= ~TS_FLUSH; 432113Sbill else { 4332456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4342468Swnj /* 4352468Swnj * Do arithmetic in a short to make up 4362468Swnj * for lost 16&17 bits. 4372468Swnj */ 4382605Swnj cntr = addr->dhcar - 4392468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4403101Swnj ndflush(&tp->t_outq, (int)cntr); 441113Sbill } 442113Sbill if (tp->t_line) 44313Sbill (*linesw[tp->t_line].l_start)(tp); 444113Sbill else 44513Sbill dhstart(tp); 44613Sbill } 44713Sbill } 44813Sbill } 44913Sbill 45013Sbill /* 45113Sbill * Start (restart) transmission on the given DH11 line. 45213Sbill */ 45313Sbill dhstart(tp) 4542395Swnj register struct tty *tp; 45513Sbill { 4562479Swnj register struct dhdevice *addr; 4572468Swnj register int car, dh, unit, nch; 4582395Swnj int s; 45913Sbill 4602468Swnj unit = minor(tp->t_dev); 4612468Swnj dh = unit >> 4; 4622468Swnj unit &= 0xf; 4632479Swnj addr = (struct dhdevice *)tp->t_addr; 4642468Swnj 46513Sbill /* 4662468Swnj * Must hold interrupts in following code to prevent 4672468Swnj * state of the tp from changing. 46813Sbill */ 46913Sbill s = spl5(); 4702468Swnj /* 4712468Swnj * If it's currently active, or delaying, no need to do anything. 4722468Swnj */ 4735406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 47413Sbill goto out; 4752468Swnj /* 4762468Swnj * If there are sleepers, and output has drained below low 4772468Swnj * water mark, wake up the sleepers. 4782468Swnj */ 4795406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 4805406Swnj if (tp->t_state&TS_ASLEEP) { 4815406Swnj tp->t_state &= ~TS_ASLEEP; 4825406Swnj wakeup((caddr_t)&tp->t_outq); 4835406Swnj } 4845406Swnj if (tp->t_wsel) { 4855406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 4865406Swnj tp->t_wsel = 0; 4875406Swnj tp->t_state &= ~TS_WCOLL; 4885406Swnj } 48913Sbill } 4902468Swnj /* 4912468Swnj * Now restart transmission unless the output queue is 4922468Swnj * empty. 4932468Swnj */ 49413Sbill if (tp->t_outq.c_cc == 0) 49513Sbill goto out; 4969549Ssam if (tp->t_flags & (RAW|LITOUT)) 49713Sbill nch = ndqb(&tp->t_outq, 0); 4982395Swnj else { 49913Sbill nch = ndqb(&tp->t_outq, 0200); 5002468Swnj /* 5012468Swnj * If first thing on queue is a delay process it. 5022468Swnj */ 50313Sbill if (nch == 0) { 50413Sbill nch = getc(&tp->t_outq); 5052468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5065406Swnj tp->t_state |= TS_TIMEOUT; 50713Sbill goto out; 50813Sbill } 50913Sbill } 5102468Swnj /* 5112468Swnj * If characters to transmit, restart transmission. 5122468Swnj */ 51313Sbill if (nch) { 5142468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5152468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5163586Sroot /* 5173586Sroot * The following nonsense with short word 5183586Sroot * is to make sure the dhbar |= word below 5193586Sroot * is done with an interlocking bisw2 instruction. 5203586Sroot */ 5213586Sroot { short word = 1 << unit; 5223586Sroot dhsar[dh] |= word; 5232468Swnj addr->dhcar = car; 52413Sbill addr->dhbcr = -nch; 5253586Sroot addr->dhbar |= word; 5263586Sroot } 5275406Swnj tp->t_state |= TS_BUSY; 52813Sbill } 5292395Swnj out: 53013Sbill splx(s); 53113Sbill } 53213Sbill 53313Sbill /* 5342468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 53513Sbill */ 53613Sbill /*ARGSUSED*/ 53713Sbill dhstop(tp, flag) 5382468Swnj register struct tty *tp; 53913Sbill { 5402479Swnj register struct dhdevice *addr; 5412395Swnj register int unit, s; 54213Sbill 5432479Swnj addr = (struct dhdevice *)tp->t_addr; 5442468Swnj /* 5452468Swnj * Block input/output interrupts while messing with state. 5462468Swnj */ 5472468Swnj s = spl5(); 5485406Swnj if (tp->t_state & TS_BUSY) { 5492468Swnj /* 5502468Swnj * Device is transmitting; stop output 5512468Swnj * by selecting the line and setting the byte 5522468Swnj * count to -1. We will clean up later 5532468Swnj * by examining the address where the dh stopped. 5542468Swnj */ 5552395Swnj unit = minor(tp->t_dev); 5562456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5575406Swnj if ((tp->t_state&TS_TTSTOP)==0) 5585406Swnj tp->t_state |= TS_FLUSH; 559113Sbill addr->dhbcr = -1; 560113Sbill } 56113Sbill splx(s); 56213Sbill } 56313Sbill 564168Sbill /* 565280Sbill * Reset state of driver if UBA reset was necessary. 566280Sbill * Reset the csrl and lpr registers on open lines, and 567280Sbill * restart transmitters. 568280Sbill */ 5692395Swnj dhreset(uban) 5702468Swnj int uban; 571280Sbill { 5722395Swnj register int dh, unit; 573280Sbill register struct tty *tp; 5742974Swnj register struct uba_device *ui; 5752421Skre int i; 576280Sbill 5772421Skre if (dh_ubinfo[uban] == 0) 5782421Skre return; 5792421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 5802770Swnj 512+nclist*sizeof (struct cblock), 0); 5812421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 5822395Swnj dh = 0; 5832643Swnj for (dh = 0; dh < NDH; dh++) { 5842421Skre ui = dhinfo[dh]; 5852421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 5862421Skre continue; 5872924Swnj printf(" dh%d", dh); 5882479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 5892479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 5902421Skre unit = dh * 16; 5912421Skre for (i = 0; i < 16; i++) { 5922421Skre tp = &dh11[unit]; 5935406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 5942421Skre dhparam(unit); 5952479Swnj dmctl(unit, DML_ON, DMSET); 5965406Swnj tp->t_state &= ~TS_BUSY; 5972421Skre dhstart(tp); 5982421Skre } 5992421Skre unit++; 600300Sbill } 601300Sbill } 602300Sbill dhtimer(); 603280Sbill } 6042395Swnj 6052468Swnj /* 6062468Swnj * At software clock interrupt time or after a UNIBUS reset 6072468Swnj * empty all the dh silos. 6082468Swnj */ 6092456Swnj dhtimer() 6102456Swnj { 6112456Swnj register int dh; 6128159Sroot register int s = spl5(); 6132456Swnj 6142643Swnj for (dh = 0; dh < NDH; dh++) 6152456Swnj dhrint(dh); 6168159Sroot splx(s); 6172456Swnj } 6182456Swnj 6192468Swnj /* 6202479Swnj * Turn on the line associated with dh dev. 6212468Swnj */ 6222468Swnj dmopen(dev) 6232468Swnj dev_t dev; 6242468Swnj { 6252468Swnj register struct tty *tp; 6262468Swnj register struct dmdevice *addr; 6272974Swnj register struct uba_device *ui; 6282468Swnj register int unit; 6292468Swnj register int dm; 6303792Swnj int s; 6312468Swnj 6322468Swnj unit = minor(dev); 6332479Swnj dm = unit >> 4; 6342468Swnj tp = &dh11[unit]; 6352566Swnj unit &= 0xf; 6362643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 6372566Swnj (dhsoftCAR[dm]&(1<<unit))) { 6385406Swnj tp->t_state |= TS_CARR_ON; 6392468Swnj return; 6402468Swnj } 6412468Swnj addr = (struct dmdevice *)ui->ui_addr; 6423792Swnj s = spl5(); 6432479Swnj addr->dmcsr &= ~DM_SE; 6442479Swnj while (addr->dmcsr & DM_BUSY) 6452468Swnj ; 6462566Swnj addr->dmcsr = unit; 6472479Swnj addr->dmlstat = DML_ON; 6482479Swnj if (addr->dmlstat&DML_CAR) 6495406Swnj tp->t_state |= TS_CARR_ON; 6503792Swnj addr->dmcsr = DM_IE|DM_SE; 6515406Swnj while ((tp->t_state&TS_CARR_ON)==0) 6522468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6533792Swnj splx(s); 6542468Swnj } 6552468Swnj 6562468Swnj /* 6572468Swnj * Dump control bits into the DM registers. 6582468Swnj */ 6592468Swnj dmctl(dev, bits, how) 6602468Swnj dev_t dev; 6612468Swnj int bits, how; 6622468Swnj { 6632974Swnj register struct uba_device *ui; 6642468Swnj register struct dmdevice *addr; 6652468Swnj register int unit, s; 6662468Swnj int dm; 6672468Swnj 6682468Swnj unit = minor(dev); 6692468Swnj dm = unit >> 4; 6702468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 6712468Swnj return; 6722468Swnj addr = (struct dmdevice *)ui->ui_addr; 6732468Swnj s = spl5(); 6742479Swnj addr->dmcsr &= ~DM_SE; 6752479Swnj while (addr->dmcsr & DM_BUSY) 6762468Swnj ; 6772468Swnj addr->dmcsr = unit & 0xf; 6782468Swnj switch(how) { 6792468Swnj case DMSET: 6802468Swnj addr->dmlstat = bits; 6812468Swnj break; 6822468Swnj case DMBIS: 6832468Swnj addr->dmlstat |= bits; 6842468Swnj break; 6852468Swnj case DMBIC: 6862468Swnj addr->dmlstat &= ~bits; 6872468Swnj break; 6882468Swnj } 6893792Swnj addr->dmcsr = DM_IE|DM_SE; 6902468Swnj splx(s); 6912468Swnj } 6922468Swnj 6932468Swnj /* 6942468Swnj * DM11 interrupt; deal with carrier transitions. 6952468Swnj */ 6962468Swnj dmintr(dm) 6972468Swnj register int dm; 6982468Swnj { 6992974Swnj register struct uba_device *ui; 7002468Swnj register struct tty *tp; 7012468Swnj register struct dmdevice *addr; 7022468Swnj 7032468Swnj ui = dminfo[dm]; 7042479Swnj if (ui == 0) 7052479Swnj return; 7062468Swnj addr = (struct dmdevice *)ui->ui_addr; 7073997Sroot if (addr->dmcsr&DM_DONE) { 7083997Sroot if (addr->dmcsr&DM_CF) { 7093997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7103997Sroot wakeup((caddr_t)&tp->t_rawq); 7119549Ssam if ((tp->t_state&TS_WOPEN) == 0 && 7129605Ssam (tp->t_flags & MDMBUF)) { 7133997Sroot if (addr->dmlstat & DML_CAR) { 7145406Swnj tp->t_state &= ~TS_TTSTOP; 7153997Sroot ttstart(tp); 7165406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7175406Swnj tp->t_state |= TS_TTSTOP; 7183997Sroot dhstop(tp, 0); 7193997Sroot } 7203997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7215406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7229605Ssam (tp->t_flags & NOHANG) == 0) { 7233997Sroot gsignal(tp->t_pgrp, SIGHUP); 7243997Sroot gsignal(tp->t_pgrp, SIGCONT); 7253997Sroot addr->dmlstat = 0; 7263997Sroot flushtty(tp, FREAD|FWRITE); 7273997Sroot } 7285406Swnj tp->t_state &= ~TS_CARR_ON; 7293997Sroot } else 7305406Swnj tp->t_state |= TS_CARR_ON; 7313997Sroot } 7323997Sroot addr->dmcsr = DM_IE|DM_SE; 7332468Swnj } 7342468Swnj } 7352625Swnj #endif 736