1*2482Swnj /* dh.c 4.18 81/02/18 */ 213Sbill 31934Swnj #include "dh.h" 41561Sbill #if NDH11 > 0 52456Swnj #define DELAY(i) { register int j = i; while (--j > 0); } 613Sbill /* 72479Swnj * DH-11/DM-11 driver 813Sbill */ 913Sbill #include "../h/param.h" 1013Sbill #include "../h/conf.h" 1113Sbill #include "../h/dir.h" 1213Sbill #include "../h/user.h" 1313Sbill #include "../h/tty.h" 1413Sbill #include "../h/map.h" 1513Sbill #include "../h/pte.h" 162395Swnj #include "../h/buf.h" 1713Sbill #include "../h/uba.h" 18113Sbill #include "../h/bk.h" 191561Sbill #include "../h/clist.h" 201786Sbill #include "../h/mx.h" 212468Swnj #include "../h/file.h" 2213Sbill 232468Swnj /* 242479Swnj * Definition of the driver for the auto-configuration program. 252479Swnj * There is one definition for the dh and one for the dm. 262468Swnj */ 272395Swnj int dhcntrlr(), dhslave(), dhrint(), dhxint(); 282395Swnj struct uba_dinfo *dhinfo[NDH11]; 292395Swnj u_short dhstd[] = { 0 }; 302395Swnj struct uba_driver dhdriver = 312479Swnj { dhcntrlr, dhslave, 0, 0, dhstd, "dh11", dhinfo }; 322395Swnj 332479Swnj int dmcntrlr(), dmslave(), dmintr(); 342479Swnj struct uba_dinfo *dminfo[NDH11]; 352479Swnj u_short dmstd[] = { 0 }; 362479Swnj struct uba_driver dmdriver = 372479Swnj { dmcntrlr, dmslave, 0, 0, dmstd, "dm11", dminfo }; 3813Sbill 392479Swnj struct dhdevice 402479Swnj { 412479Swnj union { 422479Swnj short dhcsr; /* control-status register */ 432479Swnj char dhcsrl; /* low byte for line select */ 442479Swnj } un; 452479Swnj short dhrcr; /* receive character register */ 462479Swnj short dhlpr; /* line parameter register */ 472479Swnj u_short dhcar; /* current address register */ 482479Swnj short dhbcr; /* byte count register */ 492479Swnj u_short dhbar; /* buffer active register */ 502479Swnj short dhbreak; /* break control register */ 512479Swnj short dhsilo; /* silo status register */ 522479Swnj }; 5313Sbill 542456Swnj /* Bits in dhcsr */ 552456Swnj #define DH_TI 0100000 /* transmit interrupt */ 562456Swnj #define DH_SI 0040000 /* storage interrupt */ 572456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 582456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 592456Swnj #define DH_MC 0004000 /* master clear */ 602456Swnj #define DH_NXM 0002000 /* non-existant memory */ 612456Swnj #define DH_MM 0001000 /* maintenance mode */ 622456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 632456Swnj #define DH_RI 0000200 /* receiver interrupt */ 642456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 6513Sbill 662479Swnj /* Bits in dhlpr */ 672479Swnj #define BITS6 01 682479Swnj #define BITS7 02 692479Swnj #define BITS8 03 702479Swnj #define TWOSB 04 712479Swnj #define PENABLE 020 722479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 732479Swnj #define OPAR 040 742479Swnj #define HDUPLX 040000 752479Swnj 762456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 772456Swnj 782456Swnj /* Bits in dhrcr */ 792479Swnj #define DH_PE 0010000 /* parity error */ 802479Swnj #define DH_FE 0020000 /* framing error */ 812479Swnj #define DH_DO 0040000 /* data overrun */ 822456Swnj 832479Swnj struct dmdevice 842479Swnj { 852479Swnj short dmcsr; /* control status register */ 862479Swnj short dmlstat; /* line status register */ 872479Swnj short dmpad1[2]; 882479Swnj }; 892479Swnj 902479Swnj /* bits in dm csr */ 912479Swnj #define DM_RF 0100000 /* ring flag */ 922479Swnj #define DM_CF 0040000 /* carrier flag */ 932479Swnj #define DM_CTS 0020000 /* clear to send */ 942479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 952479Swnj #define DM_CS 0004000 /* clear scan */ 962479Swnj #define DM_CM 0002000 /* clear multiplexor */ 972479Swnj #define DM_MM 0001000 /* maintenance mode */ 982479Swnj #define DM_STP 0000400 /* step */ 992479Swnj #define DM_DONE 0000200 /* scanner is done */ 1002479Swnj #define DM_IE 0000100 /* interrupt enable */ 1012479Swnj #define DM_SE 0000040 /* scan enable */ 1022479Swnj #define DM_BUSY 0000020 /* scan busy */ 1032479Swnj 1042479Swnj /* bits in dm lsr */ 1052479Swnj #define DML_RNG 0000200 /* ring */ 1062479Swnj #define DML_CAR 0000100 /* carrier detect */ 1072479Swnj #define DML_CTS 0000040 /* clear to send */ 1082479Swnj #define DML_SR 0000020 /* secondary receive */ 1092479Swnj #define DML_ST 0000010 /* secondary transmit */ 1102479Swnj #define DML_RTS 0000004 /* request to send */ 1112479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1122479Swnj #define DML_LE 0000001 /* line enable */ 1132479Swnj 1142479Swnj #define DML_ON (DML_DTR|DML_LE) 1152479Swnj #define DML_OFF (DML_LE) 1162479Swnj 11713Sbill /* 1182479Swnj * Local variables for the driver 11913Sbill */ 1202479Swnj short dhsar[NDH11]; /* software copy of last bar */ 12113Sbill 1222479Swnj struct tty dh11[NDH11*16]; 1232479Swnj int ndh11 = NDH11*16; 1242479Swnj int dhact; /* mask of active dh's */ 1252479Swnj int dhstart(), ttrstrt(); 12613Sbill 1272479Swnj /* 1282479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1292479Swnj * The UBACVT macro converts a clist space address for unibus uban 1302479Swnj * into an i/o space address for the DMA routine. 1312479Swnj */ 1322479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1332479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1342479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 13513Sbill 1362456Swnj /* 1372456Swnj * Routine for configuration to force a dh to interrupt. 1382456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1392456Swnj */ 1402468Swnj /*ARGSUSED*/ 1412395Swnj dhcntrlr(ui, reg) 1422395Swnj struct uba_dinfo *ui; 1432395Swnj caddr_t reg; 1442395Swnj { 1452468Swnj register int br, cvec; /* these are ``value-result'' */ 1462479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1472421Skre int i; 1482395Swnj 1492456Swnj dhaddr->un.dhcsr = DH_TIE; 1502456Swnj DELAY(5); 1512456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1522421Skre dhaddr->dhbcr = -1; 1532456Swnj dhaddr->dhcar = 0; 1542421Skre dhaddr->dhbar = 1; 1552456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1562421Skre dhaddr->un.dhcsr = 0; 1572456Swnj if (cvec && cvec != 0x200) 1582456Swnj cvec -= 4; /* transmit -> receive */ 159*2482Swnj #ifdef notdef 160*2482Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM; 161*2482Swnj DELAY(5); 162*2482Swnj dhaddr->un.dhcsrl |= DH_RI; 163*2482Swnj DELAY(5); 164*2482Swnj dhaddr->un.dhcsr = 0; 165*2482Swnj #endif 1662456Swnj return (1); 1672395Swnj } 1682395Swnj 1692456Swnj /* 1702456Swnj * Routine called to init slave tables. 1712456Swnj */ 1722395Swnj dhslave(ui, reg, slaveno) 1732395Swnj struct uba_dinfo *ui; 1742395Swnj caddr_t reg; 1752395Swnj { 1762395Swnj 1772456Swnj /* no tables to set up */ 1782395Swnj } 1792395Swnj 18013Sbill /* 1812479Swnj * Configuration routine to cause a dm to interrupt. 1822479Swnj */ 1832479Swnj dmcntrlr(um, addr) 1842479Swnj struct uba_minfo *um; 1852479Swnj caddr_t addr; 1862479Swnj { 1872479Swnj register int br, vec; /* value-result */ 1882479Swnj register struct dmdevice *dmaddr = (struct dmdevice *)addr; 1892479Swnj 1902479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1912479Swnj DELAY(20); 1922479Swnj dmaddr->dmcsr = 0; 1932479Swnj } 1942479Swnj 1952479Swnj dmslave(ui, addr, slave) 1962479Swnj struct uba_dinfo *ui; 1972479Swnj caddr_t addr; 1982479Swnj int slave; 1992479Swnj { 2002479Swnj 2012479Swnj /* no local state to set up */ 2022479Swnj } 2032479Swnj 2042479Swnj /* 2052468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2062468Swnj * is the first dh on this uba. Turn on this dh if this is 2072468Swnj * the first use of it. Also do a dmopen to wait for carrier. 20813Sbill */ 20913Sbill /*ARGSUSED*/ 21013Sbill dhopen(dev, flag) 2112395Swnj dev_t dev; 21213Sbill { 21313Sbill register struct tty *tp; 2142395Swnj register int unit, dh; 2152479Swnj register struct dhdevice *addr; 2162395Swnj register struct uba_dinfo *ui; 21713Sbill int s; 21813Sbill 2192395Swnj unit = minor(dev); 2202395Swnj dh = unit >> 4; 2212468Swnj if (unit >= NDH11*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 22213Sbill u.u_error = ENXIO; 22313Sbill return; 22413Sbill } 2252395Swnj tp = &dh11[unit]; 2262468Swnj if (tp->t_state&XCLUDE && u.u_uid!=0) { 2272468Swnj u.u_error = EBUSY; 2282468Swnj return; 2292468Swnj } 2302479Swnj addr = (struct dhdevice *)ui->ui_addr; 23113Sbill tp->t_addr = (caddr_t)addr; 23213Sbill tp->t_oproc = dhstart; 23313Sbill tp->t_iproc = NULL; 23413Sbill tp->t_state |= WOPEN; 2352468Swnj /* 2362468Swnj * While setting up state for this uba and this dh, 2372468Swnj * block uba resets which can clear the state. 2382468Swnj */ 2392468Swnj s = spl5(); 2402421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 241717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2422395Swnj dh_ubinfo[ui->ui_ubanum] = 2432421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2442395Swnj 512+NCLIST*sizeof(struct cblock), 0); 2452456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 24613Sbill } 2472456Swnj if ((dhact&(1<<dh)) == 0) { 2482456Swnj addr->un.dhcsr |= DH_IE; 2492468Swnj DELAY(5); 2502468Swnj dhact |= (1<<dh); 2512456Swnj addr->dhsilo = 16; 2522456Swnj } 25313Sbill splx(s); 2542468Swnj /* 2552468Swnj * If this is first open, initialze tty state to default. 2562468Swnj */ 25713Sbill if ((tp->t_state&ISOPEN) == 0) { 25813Sbill ttychars(tp); 259168Sbill if (tp->t_ispeed == 0) { 2602456Swnj tp->t_ispeed = B300; 2612456Swnj tp->t_ospeed = B300; 262168Sbill tp->t_flags = ODDP|EVENP|ECHO; 263168Sbill } 2642395Swnj dhparam(unit); 26513Sbill } 2662468Swnj /* 2672468Swnj * Wait for carrier, then process line discipline specific open. 2682468Swnj */ 26913Sbill dmopen(dev); 2702395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 27113Sbill } 27213Sbill 27313Sbill /* 2742468Swnj * Close a DH11 line, turning off the DM11. 27513Sbill */ 27613Sbill /*ARGSUSED*/ 27713Sbill dhclose(dev, flag) 2782395Swnj dev_t dev; 2792395Swnj int flag; 28013Sbill { 28113Sbill register struct tty *tp; 2822395Swnj register unit; 28313Sbill 2842395Swnj unit = minor(dev); 2852395Swnj tp = &dh11[unit]; 28613Sbill (*linesw[tp->t_line].l_close)(tp); 2872479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 28813Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 2892479Swnj dmctl(unit, DML_OFF, DMSET); 29013Sbill ttyclose(tp); 29113Sbill } 29213Sbill 29313Sbill dhread(dev) 2942395Swnj dev_t dev; 29513Sbill { 2962395Swnj register struct tty *tp; 29713Sbill 2982395Swnj tp = &dh11[minor(dev)]; 29913Sbill (*linesw[tp->t_line].l_read)(tp); 30013Sbill } 30113Sbill 30213Sbill dhwrite(dev) 3032395Swnj dev_t dev; 30413Sbill { 3052395Swnj register struct tty *tp; 30613Sbill 3072395Swnj tp = &dh11[minor(dev)]; 30813Sbill (*linesw[tp->t_line].l_write)(tp); 30913Sbill } 31013Sbill 31113Sbill /* 31213Sbill * DH11 receiver interrupt. 31313Sbill */ 3142395Swnj dhrint(dh) 3152395Swnj int dh; 31613Sbill { 31713Sbill register struct tty *tp; 3182395Swnj register c; 3192479Swnj register struct dhdevice *addr; 320117Sbill register struct tty *tp0; 3212395Swnj register struct uba_dinfo *ui; 322139Sbill int s; 32313Sbill 3242395Swnj ui = dhinfo[dh]; 3252479Swnj if (ui == 0 || ui->ui_alive == 0) 3262479Swnj return; 3272479Swnj addr = (struct dhdevice *)ui->ui_addr; 3282468Swnj tp0 = &dh11[dh<<4]; 3292468Swnj /* 3302468Swnj * Loop fetching characters from the silo for this 3312468Swnj * dh until there are no more in the silo. 3322468Swnj */ 3332468Swnj while ((c = addr->dhrcr) < 0) { 3342468Swnj tp = tp0 + ((c>>8)&0xf); 3352468Swnj if ((tp->t_state&ISOPEN)==0) { 33613Sbill wakeup((caddr_t)tp); 33713Sbill continue; 33813Sbill } 3392468Swnj if (c & DH_PE) 34013Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 34113Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 34213Sbill continue; 3432468Swnj if (c & DH_DO) 34413Sbill printf("O"); 3452468Swnj if (c & DH_FE) 3462468Swnj /* 3472468Swnj * At framing error (break) generate 3482468Swnj * a null (in raw mode, for getty), or a 3492468Swnj * interrupt (in cooked/cbreak mode). 3502468Swnj */ 35113Sbill if (tp->t_flags&RAW) 3522468Swnj c = 0; 35313Sbill else 354184Sbill c = tun.t_intrc; 355139Sbill if (tp->t_line == NETLDISC) { 356117Sbill c &= 0177; 357168Sbill BKINPUT(c, tp); 358117Sbill } else 3592468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 36013Sbill } 36113Sbill } 36213Sbill 36313Sbill /* 3642468Swnj * Ioctl for DH11. 36513Sbill */ 36613Sbill /*ARGSUSED*/ 36713Sbill dhioctl(dev, cmd, addr, flag) 3682395Swnj caddr_t addr; 36913Sbill { 37013Sbill register struct tty *tp; 3712395Swnj register unit = minor(dev); 37213Sbill 3732395Swnj tp = &dh11[unit]; 374113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 3752468Swnj if (cmd == 0) 376113Sbill return; 3771895Swnj if (ttioctl(tp, cmd, addr, flag)) { 3782468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 3792395Swnj dhparam(unit); 380168Sbill } else switch(cmd) { 381168Sbill case TIOCSBRK: 3822479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 383168Sbill break; 384168Sbill case TIOCCBRK: 3852479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 386168Sbill break; 387168Sbill case TIOCSDTR: 3882479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 389168Sbill break; 390168Sbill case TIOCCDTR: 3912479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 392168Sbill break; 393168Sbill default: 39413Sbill u.u_error = ENOTTY; 395168Sbill } 39613Sbill } 39713Sbill 39813Sbill /* 39913Sbill * Set parameters from open or stty into the DH hardware 40013Sbill * registers. 40113Sbill */ 4022395Swnj dhparam(unit) 4032395Swnj register int unit; 40413Sbill { 40513Sbill register struct tty *tp; 4062479Swnj register struct dhdevice *addr; 4072395Swnj register int lpar; 408300Sbill int s; 40913Sbill 4102395Swnj tp = &dh11[unit]; 4112479Swnj addr = (struct dhdevice *)tp->t_addr; 4122468Swnj /* 4132468Swnj * Block interrupts so parameters will be set 4142468Swnj * before the line interrupts. 4152468Swnj */ 416300Sbill s = spl5(); 4172468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 41813Sbill if ((tp->t_ispeed)==0) { 41913Sbill tp->t_state |= HUPCLS; 4202479Swnj dmctl(unit, DML_OFF, DMSET); 42113Sbill return; 42213Sbill } 4232395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4242468Swnj if ((tp->t_ispeed) == B134) 4252395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4262312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4272395Swnj lpar |= BITS8; 42813Sbill else 4292395Swnj lpar |= BITS7|PENABLE; 43013Sbill if ((tp->t_flags&EVENP) == 0) 4312395Swnj lpar |= OPAR; 4322468Swnj if ((tp->t_ospeed) == B110) 4332395Swnj lpar |= TWOSB; 4342395Swnj addr->dhlpr = lpar; 435300Sbill splx(s); 43613Sbill } 43713Sbill 43813Sbill /* 43913Sbill * DH11 transmitter interrupt. 44013Sbill * Restart each line which used to be active but has 44113Sbill * terminated transmission since the last interrupt. 44213Sbill */ 4432395Swnj dhxint(dh) 4442395Swnj int dh; 44513Sbill { 44613Sbill register struct tty *tp; 4472479Swnj register struct dhdevice *addr; 44813Sbill short ttybit, bar, *sbar; 4492395Swnj register struct uba_dinfo *ui; 4502468Swnj register int unit; 451144Sbill int s; 4522468Swnj u_short cnt; 45313Sbill 4542395Swnj ui = dhinfo[dh]; 4552479Swnj addr = (struct dhdevice *)ui->ui_addr; 4562456Swnj if (addr->un.dhcsr & DH_NXM) { 4572468Swnj DELAY(5); 4582456Swnj addr->un.dhcsr |= DH_CNI; 4592468Swnj printf("dh%d NXM\n", dh); 460105Sbill } 4612395Swnj sbar = &dhsar[dh]; 46213Sbill bar = *sbar & ~addr->dhbar; 4632395Swnj unit = dh * 16; ttybit = 1; 4642468Swnj addr->un.dhcsr &= (short)~DH_TI; 4652468Swnj for (; bar; unit++, ttybit <<= 1) { 4662468Swnj if (bar & ttybit) { 46713Sbill *sbar &= ~ttybit; 46813Sbill bar &= ~ttybit; 4692395Swnj tp = &dh11[unit]; 470113Sbill tp->t_state &= ~BUSY; 471113Sbill if (tp->t_state&FLUSH) 472113Sbill tp->t_state &= ~FLUSH; 473113Sbill else { 4742456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4752468Swnj DELAY(5); 4762468Swnj /* 4772468Swnj * Do arithmetic in a short to make up 4782468Swnj * for lost 16&17 bits. 4792468Swnj */ 4802468Swnj cnt = addr->dhcar - 4812468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4822468Swnj ndflush(&tp->t_outq, cnt); 483113Sbill } 484113Sbill if (tp->t_line) 48513Sbill (*linesw[tp->t_line].l_start)(tp); 486113Sbill else 48713Sbill dhstart(tp); 48813Sbill } 48913Sbill } 49013Sbill } 49113Sbill 49213Sbill /* 49313Sbill * Start (restart) transmission on the given DH11 line. 49413Sbill */ 49513Sbill dhstart(tp) 4962395Swnj register struct tty *tp; 49713Sbill { 4982479Swnj register struct dhdevice *addr; 4992468Swnj register int car, dh, unit, nch; 5002395Swnj int s; 50113Sbill 5022468Swnj unit = minor(tp->t_dev); 5032468Swnj dh = unit >> 4; 5042468Swnj unit &= 0xf; 5052479Swnj addr = (struct dhdevice *)tp->t_addr; 5062468Swnj 50713Sbill /* 5082468Swnj * Must hold interrupts in following code to prevent 5092468Swnj * state of the tp from changing. 51013Sbill */ 51113Sbill s = spl5(); 5122468Swnj /* 5132468Swnj * If it's currently active, or delaying, no need to do anything. 5142468Swnj */ 51513Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 51613Sbill goto out; 5172468Swnj /* 5182468Swnj * If there are sleepers, and output has drained below low 5192468Swnj * water mark, wake up the sleepers. 5202468Swnj */ 5212395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 52213Sbill tp->t_state &= ~ASLEEP; 52313Sbill if (tp->t_chan) 524168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 525168Sbill else 52613Sbill wakeup((caddr_t)&tp->t_outq); 52713Sbill } 5282468Swnj /* 5292468Swnj * Now restart transmission unless the output queue is 5302468Swnj * empty. 5312468Swnj */ 53213Sbill if (tp->t_outq.c_cc == 0) 53313Sbill goto out; 5342395Swnj if (tp->t_flags & RAW) 53513Sbill nch = ndqb(&tp->t_outq, 0); 5362395Swnj else { 53713Sbill nch = ndqb(&tp->t_outq, 0200); 5382468Swnj /* 5392468Swnj * If first thing on queue is a delay process it. 5402468Swnj */ 54113Sbill if (nch == 0) { 54213Sbill nch = getc(&tp->t_outq); 5432468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 54413Sbill tp->t_state |= TIMEOUT; 54513Sbill goto out; 54613Sbill } 54713Sbill } 5482468Swnj /* 5492468Swnj * If characters to transmit, restart transmission. 5502468Swnj */ 55113Sbill if (nch) { 5522468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5532468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5542468Swnj DELAY(5); 5552468Swnj unit = 1 << unit; 5562468Swnj dhsar[dh] |= unit; 5572468Swnj addr->dhcar = car; 55813Sbill addr->dhbcr = -nch; 5592468Swnj addr->dhbar |= unit; 56013Sbill tp->t_state |= BUSY; 56113Sbill } 5622395Swnj out: 56313Sbill splx(s); 56413Sbill } 56513Sbill 56613Sbill /* 5672468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 56813Sbill */ 56913Sbill /*ARGSUSED*/ 57013Sbill dhstop(tp, flag) 5712468Swnj register struct tty *tp; 57213Sbill { 5732479Swnj register struct dhdevice *addr; 5742395Swnj register int unit, s; 57513Sbill 5762479Swnj addr = (struct dhdevice *)tp->t_addr; 5772468Swnj /* 5782468Swnj * Block input/output interrupts while messing with state. 5792468Swnj */ 5802468Swnj s = spl5(); 581113Sbill if (tp->t_state & BUSY) { 5822468Swnj /* 5832468Swnj * Device is transmitting; stop output 5842468Swnj * by selecting the line and setting the byte 5852468Swnj * count to -1. We will clean up later 5862468Swnj * by examining the address where the dh stopped. 5872468Swnj */ 5882395Swnj unit = minor(tp->t_dev); 5892456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5902468Swnj DELAY(5); 59113Sbill if ((tp->t_state&TTSTOP)==0) 59213Sbill tp->t_state |= FLUSH; 593113Sbill addr->dhbcr = -1; 594113Sbill } 59513Sbill splx(s); 59613Sbill } 59713Sbill 598168Sbill /* 599280Sbill * Reset state of driver if UBA reset was necessary. 600280Sbill * Reset the csrl and lpr registers on open lines, and 601280Sbill * restart transmitters. 602280Sbill */ 6032395Swnj dhreset(uban) 6042468Swnj int uban; 605280Sbill { 6062395Swnj register int dh, unit; 607280Sbill register struct tty *tp; 6082395Swnj register struct uba_dinfo *ui; 6092421Skre int i; 610280Sbill 6112421Skre if (dh_ubinfo[uban] == 0) 6122421Skre return; 613280Sbill printf(" dh"); 6142421Skre ubarelse(uban, &dh_ubinfo[uban]); 6152421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6162421Skre 512+NCLIST*sizeof (struct cblock), 0); 6172421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6182395Swnj dh = 0; 6192421Skre for (dh = 0; dh < NDH11; dh++) { 6202421Skre ui = dhinfo[dh]; 6212421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6222421Skre continue; 6232479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6242468Swnj DELAY(5); 6252479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6262421Skre unit = dh * 16; 6272421Skre for (i = 0; i < 16; i++) { 6282421Skre tp = &dh11[unit]; 6292421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 6302421Skre dhparam(unit); 6312479Swnj dmctl(unit, DML_ON, DMSET); 6322421Skre tp->t_state &= ~BUSY; 6332421Skre dhstart(tp); 6342421Skre } 6352421Skre unit++; 636300Sbill } 637300Sbill } 638300Sbill dhtimer(); 639280Sbill } 6402395Swnj 6412468Swnj /* 6422468Swnj * At software clock interrupt time or after a UNIBUS reset 6432468Swnj * empty all the dh silos. 6442468Swnj */ 6452456Swnj dhtimer() 6462456Swnj { 6472456Swnj register int dh; 6482456Swnj 6492456Swnj for (dh = 0; dh < NDH11; dh++) 6502456Swnj dhrint(dh); 6512456Swnj } 6522456Swnj 6532468Swnj /* 6542479Swnj * Turn on the line associated with dh dev. 6552468Swnj */ 6562468Swnj dmopen(dev) 6572468Swnj dev_t dev; 6582468Swnj { 6592468Swnj register struct tty *tp; 6602468Swnj register struct dmdevice *addr; 6612468Swnj register struct uba_dinfo *ui; 6622468Swnj register int unit; 6632468Swnj register int dm; 6642468Swnj 6652468Swnj unit = minor(dev); 6662479Swnj dm = unit >> 4; 6672468Swnj tp = &dh11[unit]; 6682468Swnj if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 6692468Swnj tp->t_state |= CARR_ON; 6702468Swnj return; 6712468Swnj } 6722468Swnj addr = (struct dmdevice *)ui->ui_addr; 6732468Swnj spl5(); 6742479Swnj addr->dmcsr &= ~DM_SE; 6752479Swnj while (addr->dmcsr & DM_BUSY) 6762468Swnj ; 6772468Swnj addr->dmcsr = unit & 0xf; 6782479Swnj addr->dmlstat = DML_ON; 6792479Swnj if (addr->dmlstat&DML_CAR) 6802468Swnj tp->t_state |= CARR_ON; 6812479Swnj addr->dmcsr = DH_IE|DM_SE; 6822468Swnj while ((tp->t_state&CARR_ON)==0) 6832468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6842468Swnj spl0(); 6852468Swnj } 6862468Swnj 6872468Swnj /* 6882468Swnj * Dump control bits into the DM registers. 6892468Swnj */ 6902468Swnj dmctl(dev, bits, how) 6912468Swnj dev_t dev; 6922468Swnj int bits, how; 6932468Swnj { 6942468Swnj register struct uba_dinfo *ui; 6952468Swnj register struct dmdevice *addr; 6962468Swnj register int unit, s; 6972468Swnj int dm; 6982468Swnj 6992468Swnj unit = minor(dev); 7002468Swnj dm = unit >> 4; 7012468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7022468Swnj return; 7032468Swnj addr = (struct dmdevice *)ui->ui_addr; 7042468Swnj s = spl5(); 7052479Swnj addr->dmcsr &= ~DM_SE; 7062479Swnj while (addr->dmcsr & DM_BUSY) 7072468Swnj ; 7082468Swnj addr->dmcsr = unit & 0xf; 7092468Swnj switch(how) { 7102468Swnj case DMSET: 7112468Swnj addr->dmlstat = bits; 7122468Swnj break; 7132468Swnj case DMBIS: 7142468Swnj addr->dmlstat |= bits; 7152468Swnj break; 7162468Swnj case DMBIC: 7172468Swnj addr->dmlstat &= ~bits; 7182468Swnj break; 7192468Swnj } 7202479Swnj addr->dmcsr = DH_IE|DM_SE; 7212468Swnj splx(s); 7222468Swnj } 7232468Swnj 7242468Swnj /* 7252468Swnj * DM11 interrupt; deal with carrier transitions. 7262468Swnj */ 7272468Swnj dmintr(dm) 7282468Swnj register int dm; 7292468Swnj { 7302468Swnj register struct uba_dinfo *ui; 7312468Swnj register struct tty *tp; 7322468Swnj register struct dmdevice *addr; 7332468Swnj 7342468Swnj ui = dminfo[dm]; 7352479Swnj if (ui == 0) 7362479Swnj return; 7372468Swnj addr = (struct dmdevice *)ui->ui_addr; 7382479Swnj if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CF) { 7392468Swnj tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7402468Swnj wakeup((caddr_t)&tp->t_rawq); 7412468Swnj if ((tp->t_state&WOPEN)==0 && 7422468Swnj (tp->t_local&LMDMBUF)) { 7432479Swnj if (addr->dmlstat & DML_CAR) { 7442468Swnj tp->t_state &= ~TTSTOP; 7452468Swnj ttstart(tp); 7462468Swnj } else if ((tp->t_state&TTSTOP) == 0) { 7472468Swnj tp->t_state |= TTSTOP; 7482468Swnj dhstop(tp, 0); 7492468Swnj } 7502479Swnj } else if ((addr->dmlstat&DML_CAR)==0) { 7512468Swnj if ((tp->t_state&WOPEN)==0 && 7522468Swnj (tp->t_local&LNOHANG)==0) { 7532468Swnj gsignal(tp->t_pgrp, SIGHUP); 7542468Swnj gsignal(tp->t_pgrp, SIGCONT); 7552468Swnj addr->dmlstat = 0; 7562468Swnj flushtty(tp, FREAD|FWRITE); 7572468Swnj } 7582468Swnj tp->t_state &= ~CARR_ON; 7592468Swnj } else 7602468Swnj tp->t_state |= CARR_ON; 7612479Swnj addr->dmcsr = DH_IE|DM_SE; 7622468Swnj } 7632468Swnj } 764