1*3997Sroot /* dh.c 4.37 81/07/10 */ 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" 1313Sbill #include "../h/tty.h" 1413Sbill #include "../h/map.h" 1513Sbill #include "../h/pte.h" 162395Swnj #include "../h/buf.h" 172566Swnj #include "../h/vm.h" 182974Swnj #include "../h/ubareg.h" 192974Swnj #include "../h/ubavar.h" 20113Sbill #include "../h/bk.h" 211561Sbill #include "../h/clist.h" 221786Sbill #include "../h/mx.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 783441Sroot #if NBK == 0 793441Sroot #define DH_IE (DH_TIE|DH_RIE) 803441Sroot #else 812456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 823441Sroot #endif 832456Swnj 842456Swnj /* Bits in dhrcr */ 852479Swnj #define DH_PE 0010000 /* parity error */ 862479Swnj #define DH_FE 0020000 /* framing error */ 872479Swnj #define DH_DO 0040000 /* data overrun */ 882456Swnj 892479Swnj struct dmdevice 902479Swnj { 912479Swnj short dmcsr; /* control status register */ 922479Swnj short dmlstat; /* line status register */ 932479Swnj short dmpad1[2]; 942479Swnj }; 952479Swnj 962479Swnj /* bits in dm csr */ 972479Swnj #define DM_RF 0100000 /* ring flag */ 982479Swnj #define DM_CF 0040000 /* carrier flag */ 992479Swnj #define DM_CTS 0020000 /* clear to send */ 1002479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 1012479Swnj #define DM_CS 0004000 /* clear scan */ 1022479Swnj #define DM_CM 0002000 /* clear multiplexor */ 1032479Swnj #define DM_MM 0001000 /* maintenance mode */ 1042479Swnj #define DM_STP 0000400 /* step */ 1052479Swnj #define DM_DONE 0000200 /* scanner is done */ 1062479Swnj #define DM_IE 0000100 /* interrupt enable */ 1072479Swnj #define DM_SE 0000040 /* scan enable */ 1082479Swnj #define DM_BUSY 0000020 /* scan busy */ 1092479Swnj 1102479Swnj /* bits in dm lsr */ 1112479Swnj #define DML_RNG 0000200 /* ring */ 1122479Swnj #define DML_CAR 0000100 /* carrier detect */ 1132479Swnj #define DML_CTS 0000040 /* clear to send */ 1142479Swnj #define DML_SR 0000020 /* secondary receive */ 1152479Swnj #define DML_ST 0000010 /* secondary transmit */ 1162479Swnj #define DML_RTS 0000004 /* request to send */ 1172479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1182479Swnj #define DML_LE 0000001 /* line enable */ 1192479Swnj 1203792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1212479Swnj #define DML_OFF (DML_LE) 1222479Swnj 12313Sbill /* 1242479Swnj * Local variables for the driver 12513Sbill */ 1262643Swnj short dhsar[NDH]; /* software copy of last bar */ 1272643Swnj short dhsoftCAR[NDH]; 12813Sbill 1292643Swnj struct tty dh11[NDH*16]; 1302643Swnj int ndh11 = NDH*16; 1312479Swnj int dhact; /* mask of active dh's */ 1322479Swnj int dhstart(), ttrstrt(); 13313Sbill 1342479Swnj /* 1352479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1362479Swnj * The UBACVT macro converts a clist space address for unibus uban 1372479Swnj * into an i/o space address for the DMA routine. 1382479Swnj */ 1392479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1402479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1412479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 14213Sbill 1432456Swnj /* 1442456Swnj * Routine for configuration to force a dh to interrupt. 1452456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1462456Swnj */ 1472468Swnj /*ARGSUSED*/ 1482605Swnj dhprobe(reg) 1492395Swnj caddr_t reg; 1502395Swnj { 1512468Swnj register int br, cvec; /* these are ``value-result'' */ 1522479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1532395Swnj 1542605Swnj #ifdef lint 1552605Swnj br = 0; cvec = br; br = cvec; 1562605Swnj #endif 1572696Swnj #ifndef notdef 1582566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1593441Sroot DELAY(25); 1602566Swnj dhaddr->un.dhcsr = 0; 1612566Swnj #else 1622456Swnj dhaddr->un.dhcsr = DH_TIE; 1632456Swnj DELAY(5); 1642456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1652421Skre dhaddr->dhbcr = -1; 1662456Swnj dhaddr->dhcar = 0; 1672421Skre dhaddr->dhbar = 1; 1682456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1692421Skre dhaddr->un.dhcsr = 0; 1702456Swnj if (cvec && cvec != 0x200) 1712456Swnj cvec -= 4; /* transmit -> receive */ 1722482Swnj #endif 1732456Swnj return (1); 1742395Swnj } 1752395Swnj 1762456Swnj /* 1772605Swnj * Routine called to attach a dh. 1782456Swnj */ 1792605Swnj dhattach(ui) 1802974Swnj struct uba_device *ui; 1812395Swnj { 1822395Swnj 1832566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1842395Swnj } 1852395Swnj 18613Sbill /* 1872479Swnj * Configuration routine to cause a dm to interrupt. 1882479Swnj */ 1892605Swnj dmprobe(reg) 1902605Swnj caddr_t reg; 1912479Swnj { 1922479Swnj register int br, vec; /* value-result */ 1932605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1942479Swnj 1952605Swnj #ifdef lint 1963101Swnj br = 0; vec = br; br = vec; 1972605Swnj #endif 1982479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1992479Swnj DELAY(20); 2002479Swnj dmaddr->dmcsr = 0; 2012605Swnj return (1); 2022479Swnj } 2032479Swnj 2042605Swnj /*ARGSUSED*/ 2052605Swnj dmattach(ui) 2062974Swnj struct uba_device *ui; 2072479Swnj { 2082479Swnj 2092479Swnj /* no local state to set up */ 2102479Swnj } 2112479Swnj 2122479Swnj /* 2132468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2142468Swnj * is the first dh on this uba. Turn on this dh if this is 2152468Swnj * the first use of it. Also do a dmopen to wait for carrier. 21613Sbill */ 21713Sbill /*ARGSUSED*/ 21813Sbill dhopen(dev, flag) 2192395Swnj dev_t dev; 22013Sbill { 22113Sbill register struct tty *tp; 2222395Swnj register int unit, dh; 2232479Swnj register struct dhdevice *addr; 2242974Swnj register struct uba_device *ui; 22513Sbill int s; 22613Sbill 2272395Swnj unit = minor(dev); 2282395Swnj dh = unit >> 4; 2292643Swnj if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 23013Sbill u.u_error = ENXIO; 23113Sbill return; 23213Sbill } 2332395Swnj tp = &dh11[unit]; 2342468Swnj if (tp->t_state&XCLUDE && u.u_uid!=0) { 2352468Swnj u.u_error = EBUSY; 2362468Swnj return; 2372468Swnj } 2382479Swnj addr = (struct dhdevice *)ui->ui_addr; 23913Sbill tp->t_addr = (caddr_t)addr; 24013Sbill tp->t_oproc = dhstart; 24113Sbill tp->t_iproc = NULL; 24213Sbill tp->t_state |= WOPEN; 2432468Swnj /* 2442468Swnj * While setting up state for this uba and this dh, 2452468Swnj * block uba resets which can clear the state. 2462468Swnj */ 2472468Swnj s = spl5(); 2482421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 249717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2502395Swnj dh_ubinfo[ui->ui_ubanum] = 2512421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2522770Swnj 512+nclist*sizeof(struct cblock), 0); 2532456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 25413Sbill } 2552456Swnj if ((dhact&(1<<dh)) == 0) { 2562456Swnj addr->un.dhcsr |= DH_IE; 2572468Swnj dhact |= (1<<dh); 2583845Swnj #if NBK > 0 2592456Swnj addr->dhsilo = 16; 2603845Swnj #endif 2612456Swnj } 26213Sbill splx(s); 2632468Swnj /* 2642468Swnj * If this is first open, initialze tty state to default. 2652468Swnj */ 26613Sbill if ((tp->t_state&ISOPEN) == 0) { 26713Sbill ttychars(tp); 268168Sbill if (tp->t_ispeed == 0) { 2692456Swnj tp->t_ispeed = B300; 2702456Swnj tp->t_ospeed = B300; 271168Sbill tp->t_flags = ODDP|EVENP|ECHO; 272168Sbill } 2732395Swnj dhparam(unit); 27413Sbill } 2752468Swnj /* 2762468Swnj * Wait for carrier, then process line discipline specific open. 2772468Swnj */ 27813Sbill dmopen(dev); 2792395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 28013Sbill } 28113Sbill 28213Sbill /* 2832468Swnj * Close a DH11 line, turning off the DM11. 28413Sbill */ 28513Sbill /*ARGSUSED*/ 28613Sbill dhclose(dev, flag) 2872395Swnj dev_t dev; 2882395Swnj int flag; 28913Sbill { 29013Sbill register struct tty *tp; 2912395Swnj register unit; 29213Sbill 2932395Swnj unit = minor(dev); 2942395Swnj tp = &dh11[unit]; 29513Sbill (*linesw[tp->t_line].l_close)(tp); 2962479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 29713Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 2982479Swnj dmctl(unit, DML_OFF, DMSET); 29913Sbill ttyclose(tp); 30013Sbill } 30113Sbill 30213Sbill dhread(dev) 3032395Swnj dev_t dev; 30413Sbill { 3052395Swnj register struct tty *tp; 30613Sbill 3072395Swnj tp = &dh11[minor(dev)]; 30813Sbill (*linesw[tp->t_line].l_read)(tp); 30913Sbill } 31013Sbill 31113Sbill dhwrite(dev) 3122395Swnj dev_t dev; 31313Sbill { 3142395Swnj register struct tty *tp; 31513Sbill 3162395Swnj tp = &dh11[minor(dev)]; 31713Sbill (*linesw[tp->t_line].l_write)(tp); 31813Sbill } 31913Sbill 32013Sbill /* 32113Sbill * DH11 receiver interrupt. 32213Sbill */ 3232395Swnj dhrint(dh) 3242395Swnj int dh; 32513Sbill { 32613Sbill register struct tty *tp; 3272395Swnj register c; 3282479Swnj register struct dhdevice *addr; 329117Sbill register struct tty *tp0; 3302974Swnj register struct uba_device *ui; 3312924Swnj int overrun = 0; 33213Sbill 3332395Swnj ui = dhinfo[dh]; 3342479Swnj if (ui == 0 || ui->ui_alive == 0) 3352479Swnj return; 3362479Swnj addr = (struct dhdevice *)ui->ui_addr; 3372468Swnj tp0 = &dh11[dh<<4]; 3382468Swnj /* 3392468Swnj * Loop fetching characters from the silo for this 3402468Swnj * dh until there are no more in the silo. 3412468Swnj */ 3422468Swnj while ((c = addr->dhrcr) < 0) { 3432468Swnj tp = tp0 + ((c>>8)&0xf); 3442468Swnj if ((tp->t_state&ISOPEN)==0) { 34513Sbill wakeup((caddr_t)tp); 34613Sbill continue; 34713Sbill } 3482468Swnj if (c & DH_PE) 34913Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 35013Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 35113Sbill continue; 3522924Swnj if ((c & DH_DO) && overrun == 0) { 3532924Swnj printf("dh%d: silo overflow\n", dh); 3542924Swnj overrun = 1; 3552924Swnj } 3562468Swnj if (c & DH_FE) 3572468Swnj /* 3582468Swnj * At framing error (break) generate 3592468Swnj * a null (in raw mode, for getty), or a 3602468Swnj * interrupt (in cooked/cbreak mode). 3612468Swnj */ 36213Sbill if (tp->t_flags&RAW) 3632468Swnj c = 0; 36413Sbill else 365184Sbill c = tun.t_intrc; 3662730Swnj #if NBK > 0 367139Sbill if (tp->t_line == NETLDISC) { 368117Sbill c &= 0177; 369168Sbill BKINPUT(c, tp); 370117Sbill } else 3712730Swnj #endif 3722468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 37313Sbill } 37413Sbill } 37513Sbill 37613Sbill /* 3772468Swnj * Ioctl for DH11. 37813Sbill */ 37913Sbill /*ARGSUSED*/ 38013Sbill dhioctl(dev, cmd, addr, flag) 3812395Swnj caddr_t addr; 38213Sbill { 38313Sbill register struct tty *tp; 3842395Swnj register unit = minor(dev); 38513Sbill 3862395Swnj tp = &dh11[unit]; 387113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 3882468Swnj if (cmd == 0) 389113Sbill return; 3901895Swnj if (ttioctl(tp, cmd, addr, flag)) { 3912468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 3922395Swnj dhparam(unit); 393168Sbill } else switch(cmd) { 394168Sbill case TIOCSBRK: 3952479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 396168Sbill break; 397168Sbill case TIOCCBRK: 3982479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 399168Sbill break; 400168Sbill case TIOCSDTR: 4012479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 402168Sbill break; 403168Sbill case TIOCCDTR: 4042479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 405168Sbill break; 406168Sbill default: 40713Sbill u.u_error = ENOTTY; 408168Sbill } 40913Sbill } 41013Sbill 41113Sbill /* 41213Sbill * Set parameters from open or stty into the DH hardware 41313Sbill * registers. 41413Sbill */ 4152395Swnj dhparam(unit) 4162395Swnj register int unit; 41713Sbill { 41813Sbill register struct tty *tp; 4192479Swnj register struct dhdevice *addr; 4202395Swnj register int lpar; 421300Sbill int s; 42213Sbill 4232395Swnj tp = &dh11[unit]; 4242479Swnj addr = (struct dhdevice *)tp->t_addr; 4252468Swnj /* 4262468Swnj * Block interrupts so parameters will be set 4272468Swnj * before the line interrupts. 4282468Swnj */ 429300Sbill s = spl5(); 4302468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 43113Sbill if ((tp->t_ispeed)==0) { 43213Sbill tp->t_state |= HUPCLS; 4332479Swnj dmctl(unit, DML_OFF, DMSET); 43413Sbill return; 43513Sbill } 4362395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4372468Swnj if ((tp->t_ispeed) == B134) 4382395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4392312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4402395Swnj lpar |= BITS8; 44113Sbill else 4422395Swnj lpar |= BITS7|PENABLE; 44313Sbill if ((tp->t_flags&EVENP) == 0) 4442395Swnj lpar |= OPAR; 4452468Swnj if ((tp->t_ospeed) == B110) 4462395Swnj lpar |= TWOSB; 4472395Swnj addr->dhlpr = lpar; 448300Sbill splx(s); 44913Sbill } 45013Sbill 45113Sbill /* 45213Sbill * DH11 transmitter interrupt. 45313Sbill * Restart each line which used to be active but has 45413Sbill * terminated transmission since the last interrupt. 45513Sbill */ 4562395Swnj dhxint(dh) 4572395Swnj int dh; 45813Sbill { 45913Sbill register struct tty *tp; 4602479Swnj register struct dhdevice *addr; 46113Sbill short ttybit, bar, *sbar; 4622974Swnj register struct uba_device *ui; 4632468Swnj register int unit; 4642605Swnj u_short cntr; 46513Sbill 4662395Swnj ui = dhinfo[dh]; 4672479Swnj addr = (struct dhdevice *)ui->ui_addr; 4682456Swnj if (addr->un.dhcsr & DH_NXM) { 4692456Swnj addr->un.dhcsr |= DH_CNI; 4702924Swnj printf("dh%d: NXM\n", dh); 471105Sbill } 4722395Swnj sbar = &dhsar[dh]; 47313Sbill bar = *sbar & ~addr->dhbar; 4742395Swnj unit = dh * 16; ttybit = 1; 4752468Swnj addr->un.dhcsr &= (short)~DH_TI; 4762468Swnj for (; bar; unit++, ttybit <<= 1) { 4772468Swnj if (bar & ttybit) { 47813Sbill *sbar &= ~ttybit; 47913Sbill bar &= ~ttybit; 4802395Swnj tp = &dh11[unit]; 481113Sbill tp->t_state &= ~BUSY; 482113Sbill if (tp->t_state&FLUSH) 483113Sbill tp->t_state &= ~FLUSH; 484113Sbill else { 4852456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4862468Swnj /* 4872468Swnj * Do arithmetic in a short to make up 4882468Swnj * for lost 16&17 bits. 4892468Swnj */ 4902605Swnj cntr = addr->dhcar - 4912468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4923101Swnj ndflush(&tp->t_outq, (int)cntr); 493113Sbill } 494113Sbill if (tp->t_line) 49513Sbill (*linesw[tp->t_line].l_start)(tp); 496113Sbill else 49713Sbill dhstart(tp); 49813Sbill } 49913Sbill } 50013Sbill } 50113Sbill 50213Sbill /* 50313Sbill * Start (restart) transmission on the given DH11 line. 50413Sbill */ 50513Sbill dhstart(tp) 5062395Swnj register struct tty *tp; 50713Sbill { 5082479Swnj register struct dhdevice *addr; 5092468Swnj register int car, dh, unit, nch; 5102395Swnj int s; 51113Sbill 5122468Swnj unit = minor(tp->t_dev); 5132468Swnj dh = unit >> 4; 5142468Swnj unit &= 0xf; 5152479Swnj addr = (struct dhdevice *)tp->t_addr; 5162468Swnj 51713Sbill /* 5182468Swnj * Must hold interrupts in following code to prevent 5192468Swnj * state of the tp from changing. 52013Sbill */ 52113Sbill s = spl5(); 5222468Swnj /* 5232468Swnj * If it's currently active, or delaying, no need to do anything. 5242468Swnj */ 52513Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 52613Sbill goto out; 5272468Swnj /* 5282468Swnj * If there are sleepers, and output has drained below low 5292468Swnj * water mark, wake up the sleepers. 5302468Swnj */ 5312395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 53213Sbill tp->t_state &= ~ASLEEP; 53313Sbill if (tp->t_chan) 534168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 535168Sbill else 53613Sbill wakeup((caddr_t)&tp->t_outq); 53713Sbill } 5382468Swnj /* 5392468Swnj * Now restart transmission unless the output queue is 5402468Swnj * empty. 5412468Swnj */ 54213Sbill if (tp->t_outq.c_cc == 0) 54313Sbill goto out; 5443703Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 54513Sbill nch = ndqb(&tp->t_outq, 0); 5462395Swnj else { 54713Sbill nch = ndqb(&tp->t_outq, 0200); 5482468Swnj /* 5492468Swnj * If first thing on queue is a delay process it. 5502468Swnj */ 55113Sbill if (nch == 0) { 55213Sbill nch = getc(&tp->t_outq); 5532468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 55413Sbill tp->t_state |= TIMEOUT; 55513Sbill goto out; 55613Sbill } 55713Sbill } 5582468Swnj /* 5592468Swnj * If characters to transmit, restart transmission. 5602468Swnj */ 56113Sbill if (nch) { 5622468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5632468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5643586Sroot /* 5653586Sroot * The following nonsense with short word 5663586Sroot * is to make sure the dhbar |= word below 5673586Sroot * is done with an interlocking bisw2 instruction. 5683586Sroot */ 5693586Sroot { short word = 1 << unit; 5703586Sroot dhsar[dh] |= word; 5712468Swnj addr->dhcar = car; 57213Sbill addr->dhbcr = -nch; 5733586Sroot addr->dhbar |= word; 5743586Sroot } 57513Sbill tp->t_state |= BUSY; 57613Sbill } 5772395Swnj out: 57813Sbill splx(s); 57913Sbill } 58013Sbill 58113Sbill /* 5822468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 58313Sbill */ 58413Sbill /*ARGSUSED*/ 58513Sbill dhstop(tp, flag) 5862468Swnj register struct tty *tp; 58713Sbill { 5882479Swnj register struct dhdevice *addr; 5892395Swnj register int unit, s; 59013Sbill 5912479Swnj addr = (struct dhdevice *)tp->t_addr; 5922468Swnj /* 5932468Swnj * Block input/output interrupts while messing with state. 5942468Swnj */ 5952468Swnj s = spl5(); 596113Sbill if (tp->t_state & BUSY) { 5972468Swnj /* 5982468Swnj * Device is transmitting; stop output 5992468Swnj * by selecting the line and setting the byte 6002468Swnj * count to -1. We will clean up later 6012468Swnj * by examining the address where the dh stopped. 6022468Swnj */ 6032395Swnj unit = minor(tp->t_dev); 6042456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 60513Sbill if ((tp->t_state&TTSTOP)==0) 60613Sbill tp->t_state |= FLUSH; 607113Sbill addr->dhbcr = -1; 608113Sbill } 60913Sbill splx(s); 61013Sbill } 61113Sbill 612168Sbill /* 613280Sbill * Reset state of driver if UBA reset was necessary. 614280Sbill * Reset the csrl and lpr registers on open lines, and 615280Sbill * restart transmitters. 616280Sbill */ 6172395Swnj dhreset(uban) 6182468Swnj int uban; 619280Sbill { 6202395Swnj register int dh, unit; 621280Sbill register struct tty *tp; 6222974Swnj register struct uba_device *ui; 6232421Skre int i; 624280Sbill 6252421Skre if (dh_ubinfo[uban] == 0) 6262421Skre return; 6272421Skre ubarelse(uban, &dh_ubinfo[uban]); 6282421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6292770Swnj 512+nclist*sizeof (struct cblock), 0); 6302421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6312395Swnj dh = 0; 6322643Swnj for (dh = 0; dh < NDH; dh++) { 6332421Skre ui = dhinfo[dh]; 6342421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6352421Skre continue; 6362924Swnj printf(" dh%d", dh); 6372479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6383852Swnj #if NBK > 0 6392479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6403852Swnj #endif 6412421Skre unit = dh * 16; 6422421Skre for (i = 0; i < 16; i++) { 6432421Skre tp = &dh11[unit]; 6442421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 6452421Skre dhparam(unit); 6462479Swnj dmctl(unit, DML_ON, DMSET); 6472421Skre tp->t_state &= ~BUSY; 6482421Skre dhstart(tp); 6492421Skre } 6502421Skre unit++; 651300Sbill } 652300Sbill } 653300Sbill dhtimer(); 654280Sbill } 6552395Swnj 6562468Swnj /* 6572468Swnj * At software clock interrupt time or after a UNIBUS reset 6582468Swnj * empty all the dh silos. 6592468Swnj */ 6602456Swnj dhtimer() 6612456Swnj { 6622456Swnj register int dh; 6632456Swnj 6642643Swnj for (dh = 0; dh < NDH; dh++) 6652456Swnj dhrint(dh); 6662456Swnj } 6672456Swnj 6682468Swnj /* 6692479Swnj * Turn on the line associated with dh dev. 6702468Swnj */ 6712468Swnj dmopen(dev) 6722468Swnj dev_t dev; 6732468Swnj { 6742468Swnj register struct tty *tp; 6752468Swnj register struct dmdevice *addr; 6762974Swnj register struct uba_device *ui; 6772468Swnj register int unit; 6782468Swnj register int dm; 6793792Swnj int s; 6802468Swnj 6812468Swnj unit = minor(dev); 6822479Swnj dm = unit >> 4; 6832468Swnj tp = &dh11[unit]; 6842566Swnj unit &= 0xf; 6852643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 6862566Swnj (dhsoftCAR[dm]&(1<<unit))) { 6872468Swnj tp->t_state |= CARR_ON; 6882468Swnj return; 6892468Swnj } 6902468Swnj addr = (struct dmdevice *)ui->ui_addr; 6913792Swnj s = spl5(); 6922479Swnj addr->dmcsr &= ~DM_SE; 6932479Swnj while (addr->dmcsr & DM_BUSY) 6942468Swnj ; 6952566Swnj addr->dmcsr = unit; 6962479Swnj addr->dmlstat = DML_ON; 6972479Swnj if (addr->dmlstat&DML_CAR) 6982468Swnj tp->t_state |= CARR_ON; 6993792Swnj addr->dmcsr = DM_IE|DM_SE; 7002468Swnj while ((tp->t_state&CARR_ON)==0) 7012468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7023792Swnj splx(s); 7032468Swnj } 7042468Swnj 7052468Swnj /* 7062468Swnj * Dump control bits into the DM registers. 7072468Swnj */ 7082468Swnj dmctl(dev, bits, how) 7092468Swnj dev_t dev; 7102468Swnj int bits, how; 7112468Swnj { 7122974Swnj register struct uba_device *ui; 7132468Swnj register struct dmdevice *addr; 7142468Swnj register int unit, s; 7152468Swnj int dm; 7162468Swnj 7172468Swnj unit = minor(dev); 7182468Swnj dm = unit >> 4; 7192468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7202468Swnj return; 7212468Swnj addr = (struct dmdevice *)ui->ui_addr; 7222468Swnj s = spl5(); 7232479Swnj addr->dmcsr &= ~DM_SE; 7242479Swnj while (addr->dmcsr & DM_BUSY) 7252468Swnj ; 7262468Swnj addr->dmcsr = unit & 0xf; 7272468Swnj switch(how) { 7282468Swnj case DMSET: 7292468Swnj addr->dmlstat = bits; 7302468Swnj break; 7312468Swnj case DMBIS: 7322468Swnj addr->dmlstat |= bits; 7332468Swnj break; 7342468Swnj case DMBIC: 7352468Swnj addr->dmlstat &= ~bits; 7362468Swnj break; 7372468Swnj } 7383792Swnj addr->dmcsr = DM_IE|DM_SE; 7392468Swnj splx(s); 7402468Swnj } 7412468Swnj 7422468Swnj /* 7432468Swnj * DM11 interrupt; deal with carrier transitions. 7442468Swnj */ 7452468Swnj dmintr(dm) 7462468Swnj register int dm; 7472468Swnj { 7482974Swnj register struct uba_device *ui; 7492468Swnj register struct tty *tp; 7502468Swnj register struct dmdevice *addr; 7512468Swnj 7522468Swnj ui = dminfo[dm]; 7532479Swnj if (ui == 0) 7542479Swnj return; 7552468Swnj addr = (struct dmdevice *)ui->ui_addr; 756*3997Sroot if (addr->dmcsr&DM_DONE) { 757*3997Sroot if (addr->dmcsr&DM_CF) { 758*3997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 759*3997Sroot wakeup((caddr_t)&tp->t_rawq); 7602468Swnj if ((tp->t_state&WOPEN)==0 && 761*3997Sroot (tp->t_local&LMDMBUF)) { 762*3997Sroot if (addr->dmlstat & DML_CAR) { 763*3997Sroot tp->t_state &= ~TTSTOP; 764*3997Sroot ttstart(tp); 765*3997Sroot } else if ((tp->t_state&TTSTOP) == 0) { 766*3997Sroot tp->t_state |= TTSTOP; 767*3997Sroot dhstop(tp, 0); 768*3997Sroot } 769*3997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 770*3997Sroot if ((tp->t_state&WOPEN)==0 && 771*3997Sroot (tp->t_local&LNOHANG)==0) { 772*3997Sroot gsignal(tp->t_pgrp, SIGHUP); 773*3997Sroot gsignal(tp->t_pgrp, SIGCONT); 774*3997Sroot addr->dmlstat = 0; 775*3997Sroot flushtty(tp, FREAD|FWRITE); 776*3997Sroot } 777*3997Sroot tp->t_state &= ~CARR_ON; 778*3997Sroot } else 779*3997Sroot tp->t_state |= CARR_ON; 780*3997Sroot } 781*3997Sroot addr->dmcsr = DM_IE|DM_SE; 7822468Swnj } 7832468Swnj } 7842625Swnj #endif 785