1*6185Ssam /* dh.c 4.42 82/03/14 */ 213Sbill 31934Swnj #include "dh.h" 42643Swnj #if NDH > 0 513Sbill /* 62479Swnj * DH-11/DM-11 driver 713Sbill */ 82730Swnj #include "bk.h" 913Sbill #include "../h/param.h" 1013Sbill #include "../h/conf.h" 1113Sbill #include "../h/dir.h" 1213Sbill #include "../h/user.h" 13*6185Ssam #include "../h/proc.h" 1413Sbill #include "../h/tty.h" 1513Sbill #include "../h/map.h" 1613Sbill #include "../h/pte.h" 172395Swnj #include "../h/buf.h" 182566Swnj #include "../h/vm.h" 192974Swnj #include "../h/ubareg.h" 202974Swnj #include "../h/ubavar.h" 21113Sbill #include "../h/bk.h" 221561Sbill #include "../h/clist.h" 232468Swnj #include "../h/file.h" 2413Sbill 252468Swnj /* 262479Swnj * Definition of the driver for the auto-configuration program. 272479Swnj * There is one definition for the dh and one for the dm. 282468Swnj */ 292605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 302974Swnj struct uba_device *dhinfo[NDH]; 312395Swnj u_short dhstd[] = { 0 }; 322395Swnj struct uba_driver dhdriver = 332605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 342395Swnj 352605Swnj int dmprobe(), dmattach(), dmintr(); 362974Swnj struct uba_device *dminfo[NDH]; 372479Swnj u_short dmstd[] = { 0 }; 382479Swnj struct uba_driver dmdriver = 392605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4013Sbill 412479Swnj struct dhdevice 422479Swnj { 432479Swnj union { 442479Swnj short dhcsr; /* control-status register */ 452479Swnj char dhcsrl; /* low byte for line select */ 462479Swnj } un; 472479Swnj short dhrcr; /* receive character register */ 482479Swnj short dhlpr; /* line parameter register */ 492479Swnj u_short dhcar; /* current address register */ 502479Swnj short dhbcr; /* byte count register */ 512479Swnj u_short dhbar; /* buffer active register */ 522479Swnj short dhbreak; /* break control register */ 532479Swnj short dhsilo; /* silo status register */ 542479Swnj }; 5513Sbill 562456Swnj /* Bits in dhcsr */ 572456Swnj #define DH_TI 0100000 /* transmit interrupt */ 582456Swnj #define DH_SI 0040000 /* storage interrupt */ 592456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 602456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 612456Swnj #define DH_MC 0004000 /* master clear */ 622456Swnj #define DH_NXM 0002000 /* non-existant memory */ 632456Swnj #define DH_MM 0001000 /* maintenance mode */ 642456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 652456Swnj #define DH_RI 0000200 /* receiver interrupt */ 662456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 6713Sbill 682479Swnj /* Bits in dhlpr */ 692479Swnj #define BITS6 01 702479Swnj #define BITS7 02 712479Swnj #define BITS8 03 722479Swnj #define TWOSB 04 732479Swnj #define PENABLE 020 742479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 752479Swnj #define OPAR 040 762479Swnj #define HDUPLX 040000 772479Swnj 782456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 792456Swnj 802456Swnj /* Bits in dhrcr */ 812479Swnj #define DH_PE 0010000 /* parity error */ 822479Swnj #define DH_FE 0020000 /* framing error */ 832479Swnj #define DH_DO 0040000 /* data overrun */ 842456Swnj 852479Swnj struct dmdevice 862479Swnj { 872479Swnj short dmcsr; /* control status register */ 882479Swnj short dmlstat; /* line status register */ 892479Swnj short dmpad1[2]; 902479Swnj }; 912479Swnj 922479Swnj /* bits in dm csr */ 932479Swnj #define DM_RF 0100000 /* ring flag */ 942479Swnj #define DM_CF 0040000 /* carrier flag */ 952479Swnj #define DM_CTS 0020000 /* clear to send */ 962479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 972479Swnj #define DM_CS 0004000 /* clear scan */ 982479Swnj #define DM_CM 0002000 /* clear multiplexor */ 992479Swnj #define DM_MM 0001000 /* maintenance mode */ 1002479Swnj #define DM_STP 0000400 /* step */ 1012479Swnj #define DM_DONE 0000200 /* scanner is done */ 1022479Swnj #define DM_IE 0000100 /* interrupt enable */ 1032479Swnj #define DM_SE 0000040 /* scan enable */ 1042479Swnj #define DM_BUSY 0000020 /* scan busy */ 1052479Swnj 1062479Swnj /* bits in dm lsr */ 1072479Swnj #define DML_RNG 0000200 /* ring */ 1082479Swnj #define DML_CAR 0000100 /* carrier detect */ 1092479Swnj #define DML_CTS 0000040 /* clear to send */ 1102479Swnj #define DML_SR 0000020 /* secondary receive */ 1112479Swnj #define DML_ST 0000010 /* secondary transmit */ 1122479Swnj #define DML_RTS 0000004 /* request to send */ 1132479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1142479Swnj #define DML_LE 0000001 /* line enable */ 1152479Swnj 1163792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1172479Swnj #define DML_OFF (DML_LE) 1182479Swnj 11913Sbill /* 1202479Swnj * Local variables for the driver 12113Sbill */ 1222643Swnj short dhsar[NDH]; /* software copy of last bar */ 1232643Swnj short dhsoftCAR[NDH]; 12413Sbill 1252643Swnj struct tty dh11[NDH*16]; 1262643Swnj int ndh11 = NDH*16; 1272479Swnj int dhact; /* mask of active dh's */ 1282479Swnj int dhstart(), ttrstrt(); 12913Sbill 1302479Swnj /* 1312479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1322479Swnj * The UBACVT macro converts a clist space address for unibus uban 1332479Swnj * into an i/o space address for the DMA routine. 1342479Swnj */ 1352479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1362479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1372479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 13813Sbill 1392456Swnj /* 1402456Swnj * Routine for configuration to force a dh to interrupt. 1412456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1422456Swnj */ 1432468Swnj /*ARGSUSED*/ 1442605Swnj dhprobe(reg) 1452395Swnj caddr_t reg; 1462395Swnj { 1472468Swnj register int br, cvec; /* these are ``value-result'' */ 1482479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1492395Swnj 1502605Swnj #ifdef lint 1512605Swnj br = 0; cvec = br; br = cvec; 1524932Swnj dhrint(0); dhxint(0); 1532605Swnj #endif 1542696Swnj #ifndef notdef 1552566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1563441Sroot DELAY(25); 1572566Swnj dhaddr->un.dhcsr = 0; 1582566Swnj #else 1592456Swnj dhaddr->un.dhcsr = DH_TIE; 1602456Swnj DELAY(5); 1612456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1622421Skre dhaddr->dhbcr = -1; 1632456Swnj dhaddr->dhcar = 0; 1642421Skre dhaddr->dhbar = 1; 1652456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1662421Skre dhaddr->un.dhcsr = 0; 1672456Swnj if (cvec && cvec != 0x200) 1682456Swnj cvec -= 4; /* transmit -> receive */ 1692482Swnj #endif 1702456Swnj return (1); 1712395Swnj } 1722395Swnj 1732456Swnj /* 1742605Swnj * Routine called to attach a dh. 1752456Swnj */ 1762605Swnj dhattach(ui) 1772974Swnj struct uba_device *ui; 1782395Swnj { 1792395Swnj 1802566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1812395Swnj } 1822395Swnj 18313Sbill /* 1842479Swnj * Configuration routine to cause a dm to interrupt. 1852479Swnj */ 1862605Swnj dmprobe(reg) 1872605Swnj caddr_t reg; 1882479Swnj { 1892479Swnj register int br, vec; /* value-result */ 1902605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1912479Swnj 1922605Swnj #ifdef lint 1933101Swnj br = 0; vec = br; br = vec; 194*6185Ssam dmintr(0); 1952605Swnj #endif 1962479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1972479Swnj DELAY(20); 1982479Swnj dmaddr->dmcsr = 0; 1992605Swnj return (1); 2002479Swnj } 2012479Swnj 2022605Swnj /*ARGSUSED*/ 2032605Swnj dmattach(ui) 2042974Swnj struct uba_device *ui; 2052479Swnj { 2062479Swnj 2072479Swnj /* no local state to set up */ 2082479Swnj } 2092479Swnj 2102479Swnj /* 2112468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2122468Swnj * is the first dh on this uba. Turn on this dh if this is 2132468Swnj * the first use of it. Also do a dmopen to wait for carrier. 21413Sbill */ 21513Sbill /*ARGSUSED*/ 21613Sbill dhopen(dev, flag) 2172395Swnj dev_t dev; 21813Sbill { 21913Sbill register struct tty *tp; 2202395Swnj register int unit, dh; 2212479Swnj register struct dhdevice *addr; 2222974Swnj register struct uba_device *ui; 22313Sbill int s; 22413Sbill 2252395Swnj unit = minor(dev); 2262395Swnj dh = unit >> 4; 2272643Swnj if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 22813Sbill u.u_error = ENXIO; 22913Sbill return; 23013Sbill } 2312395Swnj tp = &dh11[unit]; 2325406Swnj if (tp->t_state&TS_XCLUDE && u.u_uid!=0) { 2332468Swnj u.u_error = EBUSY; 2342468Swnj return; 2352468Swnj } 2362479Swnj addr = (struct dhdevice *)ui->ui_addr; 23713Sbill tp->t_addr = (caddr_t)addr; 23813Sbill tp->t_oproc = dhstart; 2395406Swnj tp->t_state |= TS_WOPEN; 2402468Swnj /* 2412468Swnj * While setting up state for this uba and this dh, 2422468Swnj * block uba resets which can clear the state. 2432468Swnj */ 2442468Swnj s = spl5(); 2452421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 246717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2472395Swnj dh_ubinfo[ui->ui_ubanum] = 2482421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2492770Swnj 512+nclist*sizeof(struct cblock), 0); 2502456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 25113Sbill } 2522456Swnj if ((dhact&(1<<dh)) == 0) { 2532456Swnj addr->un.dhcsr |= DH_IE; 2542468Swnj dhact |= (1<<dh); 2552456Swnj addr->dhsilo = 16; 2562456Swnj } 25713Sbill splx(s); 2582468Swnj /* 2592468Swnj * If this is first open, initialze tty state to default. 2602468Swnj */ 2615406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 26213Sbill ttychars(tp); 263168Sbill if (tp->t_ispeed == 0) { 2642456Swnj tp->t_ispeed = B300; 2652456Swnj tp->t_ospeed = B300; 266168Sbill tp->t_flags = ODDP|EVENP|ECHO; 267168Sbill } 2682395Swnj dhparam(unit); 26913Sbill } 2702468Swnj /* 2712468Swnj * Wait for carrier, then process line discipline specific open. 2722468Swnj */ 27313Sbill dmopen(dev); 2742395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 27513Sbill } 27613Sbill 27713Sbill /* 2782468Swnj * Close a DH11 line, turning off the DM11. 27913Sbill */ 28013Sbill /*ARGSUSED*/ 28113Sbill dhclose(dev, flag) 2822395Swnj dev_t dev; 2832395Swnj int flag; 28413Sbill { 28513Sbill register struct tty *tp; 2862395Swnj register unit; 28713Sbill 2882395Swnj unit = minor(dev); 2892395Swnj tp = &dh11[unit]; 29013Sbill (*linesw[tp->t_line].l_close)(tp); 2912479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2925406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2932479Swnj dmctl(unit, DML_OFF, DMSET); 29413Sbill ttyclose(tp); 29513Sbill } 29613Sbill 29713Sbill dhread(dev) 2982395Swnj dev_t dev; 29913Sbill { 3002395Swnj register struct tty *tp; 30113Sbill 3022395Swnj tp = &dh11[minor(dev)]; 30313Sbill (*linesw[tp->t_line].l_read)(tp); 30413Sbill } 30513Sbill 30613Sbill dhwrite(dev) 3072395Swnj dev_t dev; 30813Sbill { 3092395Swnj register struct tty *tp; 31013Sbill 3112395Swnj tp = &dh11[minor(dev)]; 31213Sbill (*linesw[tp->t_line].l_write)(tp); 31313Sbill } 31413Sbill 31513Sbill /* 31613Sbill * DH11 receiver interrupt. 31713Sbill */ 3182395Swnj dhrint(dh) 3192395Swnj int dh; 32013Sbill { 32113Sbill register struct tty *tp; 3222395Swnj register c; 3232479Swnj register struct dhdevice *addr; 324117Sbill register struct tty *tp0; 3252974Swnj register struct uba_device *ui; 3262924Swnj int overrun = 0; 32713Sbill 3282395Swnj ui = dhinfo[dh]; 3292479Swnj if (ui == 0 || ui->ui_alive == 0) 3302479Swnj return; 3312479Swnj addr = (struct dhdevice *)ui->ui_addr; 3322468Swnj tp0 = &dh11[dh<<4]; 3332468Swnj /* 3342468Swnj * Loop fetching characters from the silo for this 3352468Swnj * dh until there are no more in the silo. 3362468Swnj */ 3372468Swnj while ((c = addr->dhrcr) < 0) { 3382468Swnj tp = tp0 + ((c>>8)&0xf); 3395406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 34013Sbill wakeup((caddr_t)tp); 34113Sbill continue; 34213Sbill } 3432468Swnj if (c & DH_PE) 34413Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 34513Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 34613Sbill continue; 3472924Swnj if ((c & DH_DO) && overrun == 0) { 3482924Swnj printf("dh%d: silo overflow\n", dh); 3492924Swnj overrun = 1; 3502924Swnj } 3512468Swnj if (c & DH_FE) 3522468Swnj /* 3532468Swnj * At framing error (break) generate 3542468Swnj * a null (in raw mode, for getty), or a 3552468Swnj * interrupt (in cooked/cbreak mode). 3562468Swnj */ 35713Sbill if (tp->t_flags&RAW) 3582468Swnj c = 0; 35913Sbill else 360184Sbill c = tun.t_intrc; 3612730Swnj #if NBK > 0 362139Sbill if (tp->t_line == NETLDISC) { 363117Sbill c &= 0177; 364168Sbill BKINPUT(c, tp); 365117Sbill } else 3662730Swnj #endif 3672468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 36813Sbill } 36913Sbill } 37013Sbill 37113Sbill /* 3722468Swnj * Ioctl for DH11. 37313Sbill */ 37413Sbill /*ARGSUSED*/ 37513Sbill dhioctl(dev, cmd, addr, flag) 3762395Swnj caddr_t addr; 37713Sbill { 37813Sbill register struct tty *tp; 3792395Swnj register unit = minor(dev); 38013Sbill 3812395Swnj tp = &dh11[unit]; 382113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 3832468Swnj if (cmd == 0) 384113Sbill return; 3851895Swnj if (ttioctl(tp, cmd, addr, flag)) { 3862468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 3872395Swnj dhparam(unit); 388168Sbill } else switch(cmd) { 389168Sbill case TIOCSBRK: 3902479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 391168Sbill break; 392168Sbill case TIOCCBRK: 3932479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 394168Sbill break; 395168Sbill case TIOCSDTR: 3962479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 397168Sbill break; 398168Sbill case TIOCCDTR: 3992479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 400168Sbill break; 401168Sbill default: 40213Sbill u.u_error = ENOTTY; 403168Sbill } 40413Sbill } 40513Sbill 40613Sbill /* 40713Sbill * Set parameters from open or stty into the DH hardware 40813Sbill * registers. 40913Sbill */ 4102395Swnj dhparam(unit) 4112395Swnj register int unit; 41213Sbill { 41313Sbill register struct tty *tp; 4142479Swnj register struct dhdevice *addr; 4152395Swnj register int lpar; 416300Sbill int s; 41713Sbill 4182395Swnj tp = &dh11[unit]; 4192479Swnj addr = (struct dhdevice *)tp->t_addr; 4202468Swnj /* 4212468Swnj * Block interrupts so parameters will be set 4222468Swnj * before the line interrupts. 4232468Swnj */ 424300Sbill s = spl5(); 4252468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 42613Sbill if ((tp->t_ispeed)==0) { 4275406Swnj tp->t_state |= TS_HUPCLS; 4282479Swnj dmctl(unit, DML_OFF, DMSET); 42913Sbill return; 43013Sbill } 4312395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4322468Swnj if ((tp->t_ispeed) == B134) 4332395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4342312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4352395Swnj lpar |= BITS8; 43613Sbill else 4372395Swnj lpar |= BITS7|PENABLE; 43813Sbill if ((tp->t_flags&EVENP) == 0) 4392395Swnj lpar |= OPAR; 4402468Swnj if ((tp->t_ospeed) == B110) 4412395Swnj lpar |= TWOSB; 4422395Swnj addr->dhlpr = lpar; 443300Sbill splx(s); 44413Sbill } 44513Sbill 44613Sbill /* 44713Sbill * DH11 transmitter interrupt. 44813Sbill * Restart each line which used to be active but has 44913Sbill * terminated transmission since the last interrupt. 45013Sbill */ 4512395Swnj dhxint(dh) 4522395Swnj int dh; 45313Sbill { 45413Sbill register struct tty *tp; 4552479Swnj register struct dhdevice *addr; 45613Sbill short ttybit, bar, *sbar; 4572974Swnj register struct uba_device *ui; 4582468Swnj register int unit; 4592605Swnj u_short cntr; 46013Sbill 4612395Swnj ui = dhinfo[dh]; 4622479Swnj addr = (struct dhdevice *)ui->ui_addr; 4632456Swnj if (addr->un.dhcsr & DH_NXM) { 4642456Swnj addr->un.dhcsr |= DH_CNI; 4652924Swnj printf("dh%d: NXM\n", dh); 466105Sbill } 4672395Swnj sbar = &dhsar[dh]; 46813Sbill bar = *sbar & ~addr->dhbar; 4692395Swnj unit = dh * 16; ttybit = 1; 4702468Swnj addr->un.dhcsr &= (short)~DH_TI; 4712468Swnj for (; bar; unit++, ttybit <<= 1) { 4722468Swnj if (bar & ttybit) { 47313Sbill *sbar &= ~ttybit; 47413Sbill bar &= ~ttybit; 4752395Swnj tp = &dh11[unit]; 4765406Swnj tp->t_state &= ~TS_BUSY; 4775406Swnj if (tp->t_state&TS_FLUSH) 4785406Swnj tp->t_state &= ~TS_FLUSH; 479113Sbill else { 4802456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4812468Swnj /* 4822468Swnj * Do arithmetic in a short to make up 4832468Swnj * for lost 16&17 bits. 4842468Swnj */ 4852605Swnj cntr = addr->dhcar - 4862468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4873101Swnj ndflush(&tp->t_outq, (int)cntr); 488113Sbill } 489113Sbill if (tp->t_line) 49013Sbill (*linesw[tp->t_line].l_start)(tp); 491113Sbill else 49213Sbill dhstart(tp); 49313Sbill } 49413Sbill } 49513Sbill } 49613Sbill 49713Sbill /* 49813Sbill * Start (restart) transmission on the given DH11 line. 49913Sbill */ 50013Sbill dhstart(tp) 5012395Swnj register struct tty *tp; 50213Sbill { 5032479Swnj register struct dhdevice *addr; 5042468Swnj register int car, dh, unit, nch; 5052395Swnj int s; 50613Sbill 5072468Swnj unit = minor(tp->t_dev); 5082468Swnj dh = unit >> 4; 5092468Swnj unit &= 0xf; 5102479Swnj addr = (struct dhdevice *)tp->t_addr; 5112468Swnj 51213Sbill /* 5132468Swnj * Must hold interrupts in following code to prevent 5142468Swnj * state of the tp from changing. 51513Sbill */ 51613Sbill s = spl5(); 5172468Swnj /* 5182468Swnj * If it's currently active, or delaying, no need to do anything. 5192468Swnj */ 5205406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 52113Sbill goto out; 5222468Swnj /* 5232468Swnj * If there are sleepers, and output has drained below low 5242468Swnj * water mark, wake up the sleepers. 5252468Swnj */ 5265406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5275406Swnj if (tp->t_state&TS_ASLEEP) { 5285406Swnj tp->t_state &= ~TS_ASLEEP; 5295406Swnj wakeup((caddr_t)&tp->t_outq); 5305406Swnj } 5315406Swnj if (tp->t_wsel) { 5325406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5335406Swnj tp->t_wsel = 0; 5345406Swnj tp->t_state &= ~TS_WCOLL; 5355406Swnj } 53613Sbill } 5372468Swnj /* 5382468Swnj * Now restart transmission unless the output queue is 5392468Swnj * empty. 5402468Swnj */ 54113Sbill if (tp->t_outq.c_cc == 0) 54213Sbill goto out; 5433703Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 54413Sbill nch = ndqb(&tp->t_outq, 0); 5452395Swnj else { 54613Sbill nch = ndqb(&tp->t_outq, 0200); 5472468Swnj /* 5482468Swnj * If first thing on queue is a delay process it. 5492468Swnj */ 55013Sbill if (nch == 0) { 55113Sbill nch = getc(&tp->t_outq); 5522468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5535406Swnj tp->t_state |= TS_TIMEOUT; 55413Sbill goto out; 55513Sbill } 55613Sbill } 5572468Swnj /* 5582468Swnj * If characters to transmit, restart transmission. 5592468Swnj */ 56013Sbill if (nch) { 5612468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5622468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5633586Sroot /* 5643586Sroot * The following nonsense with short word 5653586Sroot * is to make sure the dhbar |= word below 5663586Sroot * is done with an interlocking bisw2 instruction. 5673586Sroot */ 5683586Sroot { short word = 1 << unit; 5693586Sroot dhsar[dh] |= word; 5702468Swnj addr->dhcar = car; 57113Sbill addr->dhbcr = -nch; 5723586Sroot addr->dhbar |= word; 5733586Sroot } 5745406Swnj tp->t_state |= TS_BUSY; 57513Sbill } 5762395Swnj out: 57713Sbill splx(s); 57813Sbill } 57913Sbill 58013Sbill /* 5812468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 58213Sbill */ 58313Sbill /*ARGSUSED*/ 58413Sbill dhstop(tp, flag) 5852468Swnj register struct tty *tp; 58613Sbill { 5872479Swnj register struct dhdevice *addr; 5882395Swnj register int unit, s; 58913Sbill 5902479Swnj addr = (struct dhdevice *)tp->t_addr; 5912468Swnj /* 5922468Swnj * Block input/output interrupts while messing with state. 5932468Swnj */ 5942468Swnj s = spl5(); 5955406Swnj if (tp->t_state & TS_BUSY) { 5962468Swnj /* 5972468Swnj * Device is transmitting; stop output 5982468Swnj * by selecting the line and setting the byte 5992468Swnj * count to -1. We will clean up later 6002468Swnj * by examining the address where the dh stopped. 6012468Swnj */ 6022395Swnj unit = minor(tp->t_dev); 6032456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6045406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6055406Swnj tp->t_state |= TS_FLUSH; 606113Sbill addr->dhbcr = -1; 607113Sbill } 60813Sbill splx(s); 60913Sbill } 61013Sbill 611168Sbill /* 612280Sbill * Reset state of driver if UBA reset was necessary. 613280Sbill * Reset the csrl and lpr registers on open lines, and 614280Sbill * restart transmitters. 615280Sbill */ 6162395Swnj dhreset(uban) 6172468Swnj int uban; 618280Sbill { 6192395Swnj register int dh, unit; 620280Sbill register struct tty *tp; 6212974Swnj register struct uba_device *ui; 6222421Skre int i; 623280Sbill 6242421Skre if (dh_ubinfo[uban] == 0) 6252421Skre return; 6262421Skre ubarelse(uban, &dh_ubinfo[uban]); 6272421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6282770Swnj 512+nclist*sizeof (struct cblock), 0); 6292421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6302395Swnj dh = 0; 6312643Swnj for (dh = 0; dh < NDH; dh++) { 6322421Skre ui = dhinfo[dh]; 6332421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6342421Skre continue; 6352924Swnj printf(" dh%d", dh); 6362479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6372479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6382421Skre unit = dh * 16; 6392421Skre for (i = 0; i < 16; i++) { 6402421Skre tp = &dh11[unit]; 6415406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6422421Skre dhparam(unit); 6432479Swnj dmctl(unit, DML_ON, DMSET); 6445406Swnj tp->t_state &= ~TS_BUSY; 6452421Skre dhstart(tp); 6462421Skre } 6472421Skre unit++; 648300Sbill } 649300Sbill } 650300Sbill dhtimer(); 651280Sbill } 6522395Swnj 6532468Swnj /* 6542468Swnj * At software clock interrupt time or after a UNIBUS reset 6552468Swnj * empty all the dh silos. 6562468Swnj */ 6572456Swnj dhtimer() 6582456Swnj { 6592456Swnj register int dh; 6602456Swnj 6612643Swnj for (dh = 0; dh < NDH; dh++) 6622456Swnj dhrint(dh); 6632456Swnj } 6642456Swnj 6652468Swnj /* 6662479Swnj * Turn on the line associated with dh dev. 6672468Swnj */ 6682468Swnj dmopen(dev) 6692468Swnj dev_t dev; 6702468Swnj { 6712468Swnj register struct tty *tp; 6722468Swnj register struct dmdevice *addr; 6732974Swnj register struct uba_device *ui; 6742468Swnj register int unit; 6752468Swnj register int dm; 6763792Swnj int s; 6772468Swnj 6782468Swnj unit = minor(dev); 6792479Swnj dm = unit >> 4; 6802468Swnj tp = &dh11[unit]; 6812566Swnj unit &= 0xf; 6822643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 6832566Swnj (dhsoftCAR[dm]&(1<<unit))) { 6845406Swnj tp->t_state |= TS_CARR_ON; 6852468Swnj return; 6862468Swnj } 6872468Swnj addr = (struct dmdevice *)ui->ui_addr; 6883792Swnj s = spl5(); 6892479Swnj addr->dmcsr &= ~DM_SE; 6902479Swnj while (addr->dmcsr & DM_BUSY) 6912468Swnj ; 6922566Swnj addr->dmcsr = unit; 6932479Swnj addr->dmlstat = DML_ON; 6942479Swnj if (addr->dmlstat&DML_CAR) 6955406Swnj tp->t_state |= TS_CARR_ON; 6963792Swnj addr->dmcsr = DM_IE|DM_SE; 6975406Swnj while ((tp->t_state&TS_CARR_ON)==0) 6982468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6993792Swnj splx(s); 7002468Swnj } 7012468Swnj 7022468Swnj /* 7032468Swnj * Dump control bits into the DM registers. 7042468Swnj */ 7052468Swnj dmctl(dev, bits, how) 7062468Swnj dev_t dev; 7072468Swnj int bits, how; 7082468Swnj { 7092974Swnj register struct uba_device *ui; 7102468Swnj register struct dmdevice *addr; 7112468Swnj register int unit, s; 7122468Swnj int dm; 7132468Swnj 7142468Swnj unit = minor(dev); 7152468Swnj dm = unit >> 4; 7162468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7172468Swnj return; 7182468Swnj addr = (struct dmdevice *)ui->ui_addr; 7192468Swnj s = spl5(); 7202479Swnj addr->dmcsr &= ~DM_SE; 7212479Swnj while (addr->dmcsr & DM_BUSY) 7222468Swnj ; 7232468Swnj addr->dmcsr = unit & 0xf; 7242468Swnj switch(how) { 7252468Swnj case DMSET: 7262468Swnj addr->dmlstat = bits; 7272468Swnj break; 7282468Swnj case DMBIS: 7292468Swnj addr->dmlstat |= bits; 7302468Swnj break; 7312468Swnj case DMBIC: 7322468Swnj addr->dmlstat &= ~bits; 7332468Swnj break; 7342468Swnj } 7353792Swnj addr->dmcsr = DM_IE|DM_SE; 7362468Swnj splx(s); 7372468Swnj } 7382468Swnj 7392468Swnj /* 7402468Swnj * DM11 interrupt; deal with carrier transitions. 7412468Swnj */ 7422468Swnj dmintr(dm) 7432468Swnj register int dm; 7442468Swnj { 7452974Swnj register struct uba_device *ui; 7462468Swnj register struct tty *tp; 7472468Swnj register struct dmdevice *addr; 7482468Swnj 7492468Swnj ui = dminfo[dm]; 7502479Swnj if (ui == 0) 7512479Swnj return; 7522468Swnj addr = (struct dmdevice *)ui->ui_addr; 7533997Sroot if (addr->dmcsr&DM_DONE) { 7543997Sroot if (addr->dmcsr&DM_CF) { 7553997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7563997Sroot wakeup((caddr_t)&tp->t_rawq); 7575406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7583997Sroot (tp->t_local&LMDMBUF)) { 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 } 7663997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7675406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7683997Sroot (tp->t_local&LNOHANG)==0) { 7693997Sroot gsignal(tp->t_pgrp, SIGHUP); 7703997Sroot gsignal(tp->t_pgrp, SIGCONT); 7713997Sroot addr->dmlstat = 0; 7723997Sroot flushtty(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