1*4932Swnj /* dh.c 4.40 81/11/18 */ 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" 222468Swnj #include "../h/file.h" 2313Sbill 242468Swnj /* 252479Swnj * Definition of the driver for the auto-configuration program. 262479Swnj * There is one definition for the dh and one for the dm. 272468Swnj */ 282605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 292974Swnj struct uba_device *dhinfo[NDH]; 302395Swnj u_short dhstd[] = { 0 }; 312395Swnj struct uba_driver dhdriver = 322605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 332395Swnj 342605Swnj int dmprobe(), dmattach(), dmintr(); 352974Swnj struct uba_device *dminfo[NDH]; 362479Swnj u_short dmstd[] = { 0 }; 372479Swnj struct uba_driver dmdriver = 382605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 3913Sbill 402479Swnj struct dhdevice 412479Swnj { 422479Swnj union { 432479Swnj short dhcsr; /* control-status register */ 442479Swnj char dhcsrl; /* low byte for line select */ 452479Swnj } un; 462479Swnj short dhrcr; /* receive character register */ 472479Swnj short dhlpr; /* line parameter register */ 482479Swnj u_short dhcar; /* current address register */ 492479Swnj short dhbcr; /* byte count register */ 502479Swnj u_short dhbar; /* buffer active register */ 512479Swnj short dhbreak; /* break control register */ 522479Swnj short dhsilo; /* silo status register */ 532479Swnj }; 5413Sbill 552456Swnj /* Bits in dhcsr */ 562456Swnj #define DH_TI 0100000 /* transmit interrupt */ 572456Swnj #define DH_SI 0040000 /* storage interrupt */ 582456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 592456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 602456Swnj #define DH_MC 0004000 /* master clear */ 612456Swnj #define DH_NXM 0002000 /* non-existant memory */ 622456Swnj #define DH_MM 0001000 /* maintenance mode */ 632456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 642456Swnj #define DH_RI 0000200 /* receiver interrupt */ 652456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 6613Sbill 672479Swnj /* Bits in dhlpr */ 682479Swnj #define BITS6 01 692479Swnj #define BITS7 02 702479Swnj #define BITS8 03 712479Swnj #define TWOSB 04 722479Swnj #define PENABLE 020 732479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 742479Swnj #define OPAR 040 752479Swnj #define HDUPLX 040000 762479Swnj 772456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 782456Swnj 792456Swnj /* Bits in dhrcr */ 802479Swnj #define DH_PE 0010000 /* parity error */ 812479Swnj #define DH_FE 0020000 /* framing error */ 822479Swnj #define DH_DO 0040000 /* data overrun */ 832456Swnj 842479Swnj struct dmdevice 852479Swnj { 862479Swnj short dmcsr; /* control status register */ 872479Swnj short dmlstat; /* line status register */ 882479Swnj short dmpad1[2]; 892479Swnj }; 902479Swnj 912479Swnj /* bits in dm csr */ 922479Swnj #define DM_RF 0100000 /* ring flag */ 932479Swnj #define DM_CF 0040000 /* carrier flag */ 942479Swnj #define DM_CTS 0020000 /* clear to send */ 952479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 962479Swnj #define DM_CS 0004000 /* clear scan */ 972479Swnj #define DM_CM 0002000 /* clear multiplexor */ 982479Swnj #define DM_MM 0001000 /* maintenance mode */ 992479Swnj #define DM_STP 0000400 /* step */ 1002479Swnj #define DM_DONE 0000200 /* scanner is done */ 1012479Swnj #define DM_IE 0000100 /* interrupt enable */ 1022479Swnj #define DM_SE 0000040 /* scan enable */ 1032479Swnj #define DM_BUSY 0000020 /* scan busy */ 1042479Swnj 1052479Swnj /* bits in dm lsr */ 1062479Swnj #define DML_RNG 0000200 /* ring */ 1072479Swnj #define DML_CAR 0000100 /* carrier detect */ 1082479Swnj #define DML_CTS 0000040 /* clear to send */ 1092479Swnj #define DML_SR 0000020 /* secondary receive */ 1102479Swnj #define DML_ST 0000010 /* secondary transmit */ 1112479Swnj #define DML_RTS 0000004 /* request to send */ 1122479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1132479Swnj #define DML_LE 0000001 /* line enable */ 1142479Swnj 1153792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1162479Swnj #define DML_OFF (DML_LE) 1172479Swnj 11813Sbill /* 1192479Swnj * Local variables for the driver 12013Sbill */ 1212643Swnj short dhsar[NDH]; /* software copy of last bar */ 1222643Swnj short dhsoftCAR[NDH]; 12313Sbill 1242643Swnj struct tty dh11[NDH*16]; 1252643Swnj int ndh11 = NDH*16; 1262479Swnj int dhact; /* mask of active dh's */ 1272479Swnj int dhstart(), ttrstrt(); 12813Sbill 1292479Swnj /* 1302479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1312479Swnj * The UBACVT macro converts a clist space address for unibus uban 1322479Swnj * into an i/o space address for the DMA routine. 1332479Swnj */ 1342479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1352479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1362479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 13713Sbill 1382456Swnj /* 1392456Swnj * Routine for configuration to force a dh to interrupt. 1402456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1412456Swnj */ 1422468Swnj /*ARGSUSED*/ 1432605Swnj dhprobe(reg) 1442395Swnj caddr_t reg; 1452395Swnj { 1462468Swnj register int br, cvec; /* these are ``value-result'' */ 1472479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1482395Swnj 1492605Swnj #ifdef lint 1502605Swnj br = 0; cvec = br; br = cvec; 151*4932Swnj dhrint(0); dhxint(0); 1522605Swnj #endif 1532696Swnj #ifndef notdef 1542566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1553441Sroot DELAY(25); 1562566Swnj dhaddr->un.dhcsr = 0; 1572566Swnj #else 1582456Swnj dhaddr->un.dhcsr = DH_TIE; 1592456Swnj DELAY(5); 1602456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1612421Skre dhaddr->dhbcr = -1; 1622456Swnj dhaddr->dhcar = 0; 1632421Skre dhaddr->dhbar = 1; 1642456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1652421Skre dhaddr->un.dhcsr = 0; 1662456Swnj if (cvec && cvec != 0x200) 1672456Swnj cvec -= 4; /* transmit -> receive */ 1682482Swnj #endif 1692456Swnj return (1); 1702395Swnj } 1712395Swnj 1722456Swnj /* 1732605Swnj * Routine called to attach a dh. 1742456Swnj */ 1752605Swnj dhattach(ui) 1762974Swnj struct uba_device *ui; 1772395Swnj { 1782395Swnj 1792566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1802395Swnj } 1812395Swnj 18213Sbill /* 1832479Swnj * Configuration routine to cause a dm to interrupt. 1842479Swnj */ 1852605Swnj dmprobe(reg) 1862605Swnj caddr_t reg; 1872479Swnj { 1882479Swnj register int br, vec; /* value-result */ 1892605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1902479Swnj 1912605Swnj #ifdef lint 1923101Swnj br = 0; vec = br; br = vec; 193*4932Swnj dmintr(); 1942605Swnj #endif 1952479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1962479Swnj DELAY(20); 1972479Swnj dmaddr->dmcsr = 0; 1982605Swnj return (1); 1992479Swnj } 2002479Swnj 2012605Swnj /*ARGSUSED*/ 2022605Swnj dmattach(ui) 2032974Swnj struct uba_device *ui; 2042479Swnj { 2052479Swnj 2062479Swnj /* no local state to set up */ 2072479Swnj } 2082479Swnj 2092479Swnj /* 2102468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2112468Swnj * is the first dh on this uba. Turn on this dh if this is 2122468Swnj * the first use of it. Also do a dmopen to wait for carrier. 21313Sbill */ 21413Sbill /*ARGSUSED*/ 21513Sbill dhopen(dev, flag) 2162395Swnj dev_t dev; 21713Sbill { 21813Sbill register struct tty *tp; 2192395Swnj register int unit, dh; 2202479Swnj register struct dhdevice *addr; 2212974Swnj register struct uba_device *ui; 22213Sbill int s; 22313Sbill 2242395Swnj unit = minor(dev); 2252395Swnj dh = unit >> 4; 2262643Swnj if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 22713Sbill u.u_error = ENXIO; 22813Sbill return; 22913Sbill } 2302395Swnj tp = &dh11[unit]; 2312468Swnj if (tp->t_state&XCLUDE && u.u_uid!=0) { 2322468Swnj u.u_error = EBUSY; 2332468Swnj return; 2342468Swnj } 2352479Swnj addr = (struct dhdevice *)ui->ui_addr; 23613Sbill tp->t_addr = (caddr_t)addr; 23713Sbill tp->t_oproc = dhstart; 23813Sbill tp->t_state |= WOPEN; 2392468Swnj /* 2402468Swnj * While setting up state for this uba and this dh, 2412468Swnj * block uba resets which can clear the state. 2422468Swnj */ 2432468Swnj s = spl5(); 2442421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 245717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2462395Swnj dh_ubinfo[ui->ui_ubanum] = 2472421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2482770Swnj 512+nclist*sizeof(struct cblock), 0); 2492456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 25013Sbill } 2512456Swnj if ((dhact&(1<<dh)) == 0) { 2522456Swnj addr->un.dhcsr |= DH_IE; 2532468Swnj dhact |= (1<<dh); 2542456Swnj addr->dhsilo = 16; 2552456Swnj } 25613Sbill splx(s); 2572468Swnj /* 2582468Swnj * If this is first open, initialze tty state to default. 2592468Swnj */ 26013Sbill if ((tp->t_state&ISOPEN) == 0) { 26113Sbill ttychars(tp); 262168Sbill if (tp->t_ispeed == 0) { 2632456Swnj tp->t_ispeed = B300; 2642456Swnj tp->t_ospeed = B300; 265168Sbill tp->t_flags = ODDP|EVENP|ECHO; 266168Sbill } 2672395Swnj dhparam(unit); 26813Sbill } 2692468Swnj /* 2702468Swnj * Wait for carrier, then process line discipline specific open. 2712468Swnj */ 27213Sbill dmopen(dev); 2732395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 27413Sbill } 27513Sbill 27613Sbill /* 2772468Swnj * Close a DH11 line, turning off the DM11. 27813Sbill */ 27913Sbill /*ARGSUSED*/ 28013Sbill dhclose(dev, flag) 2812395Swnj dev_t dev; 2822395Swnj int flag; 28313Sbill { 28413Sbill register struct tty *tp; 2852395Swnj register unit; 28613Sbill 2872395Swnj unit = minor(dev); 2882395Swnj tp = &dh11[unit]; 28913Sbill (*linesw[tp->t_line].l_close)(tp); 2902479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 29113Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 2922479Swnj dmctl(unit, DML_OFF, DMSET); 29313Sbill ttyclose(tp); 29413Sbill } 29513Sbill 29613Sbill dhread(dev) 2972395Swnj dev_t dev; 29813Sbill { 2992395Swnj register struct tty *tp; 30013Sbill 3012395Swnj tp = &dh11[minor(dev)]; 30213Sbill (*linesw[tp->t_line].l_read)(tp); 30313Sbill } 30413Sbill 30513Sbill dhwrite(dev) 3062395Swnj dev_t dev; 30713Sbill { 3082395Swnj register struct tty *tp; 30913Sbill 3102395Swnj tp = &dh11[minor(dev)]; 31113Sbill (*linesw[tp->t_line].l_write)(tp); 31213Sbill } 31313Sbill 31413Sbill /* 31513Sbill * DH11 receiver interrupt. 31613Sbill */ 3172395Swnj dhrint(dh) 3182395Swnj int dh; 31913Sbill { 32013Sbill register struct tty *tp; 3212395Swnj register c; 3222479Swnj register struct dhdevice *addr; 323117Sbill register struct tty *tp0; 3242974Swnj register struct uba_device *ui; 3252924Swnj int overrun = 0; 32613Sbill 3272395Swnj ui = dhinfo[dh]; 3282479Swnj if (ui == 0 || ui->ui_alive == 0) 3292479Swnj return; 3302479Swnj addr = (struct dhdevice *)ui->ui_addr; 3312468Swnj tp0 = &dh11[dh<<4]; 3322468Swnj /* 3332468Swnj * Loop fetching characters from the silo for this 3342468Swnj * dh until there are no more in the silo. 3352468Swnj */ 3362468Swnj while ((c = addr->dhrcr) < 0) { 3372468Swnj tp = tp0 + ((c>>8)&0xf); 3382468Swnj if ((tp->t_state&ISOPEN)==0) { 33913Sbill wakeup((caddr_t)tp); 34013Sbill continue; 34113Sbill } 3422468Swnj if (c & DH_PE) 34313Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 34413Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 34513Sbill continue; 3462924Swnj if ((c & DH_DO) && overrun == 0) { 3472924Swnj printf("dh%d: silo overflow\n", dh); 3482924Swnj overrun = 1; 3492924Swnj } 3502468Swnj if (c & DH_FE) 3512468Swnj /* 3522468Swnj * At framing error (break) generate 3532468Swnj * a null (in raw mode, for getty), or a 3542468Swnj * interrupt (in cooked/cbreak mode). 3552468Swnj */ 35613Sbill if (tp->t_flags&RAW) 3572468Swnj c = 0; 35813Sbill else 359184Sbill c = tun.t_intrc; 3602730Swnj #if NBK > 0 361139Sbill if (tp->t_line == NETLDISC) { 362117Sbill c &= 0177; 363168Sbill BKINPUT(c, tp); 364117Sbill } else 3652730Swnj #endif 3662468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 36713Sbill } 36813Sbill } 36913Sbill 37013Sbill /* 3712468Swnj * Ioctl for DH11. 37213Sbill */ 37313Sbill /*ARGSUSED*/ 37413Sbill dhioctl(dev, cmd, addr, flag) 3752395Swnj caddr_t addr; 37613Sbill { 37713Sbill register struct tty *tp; 3782395Swnj register unit = minor(dev); 37913Sbill 3802395Swnj tp = &dh11[unit]; 381113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 3822468Swnj if (cmd == 0) 383113Sbill return; 3841895Swnj if (ttioctl(tp, cmd, addr, flag)) { 3852468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 3862395Swnj dhparam(unit); 387168Sbill } else switch(cmd) { 388168Sbill case TIOCSBRK: 3892479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 390168Sbill break; 391168Sbill case TIOCCBRK: 3922479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 393168Sbill break; 394168Sbill case TIOCSDTR: 3952479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 396168Sbill break; 397168Sbill case TIOCCDTR: 3982479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 399168Sbill break; 400168Sbill default: 40113Sbill u.u_error = ENOTTY; 402168Sbill } 40313Sbill } 40413Sbill 40513Sbill /* 40613Sbill * Set parameters from open or stty into the DH hardware 40713Sbill * registers. 40813Sbill */ 4092395Swnj dhparam(unit) 4102395Swnj register int unit; 41113Sbill { 41213Sbill register struct tty *tp; 4132479Swnj register struct dhdevice *addr; 4142395Swnj register int lpar; 415300Sbill int s; 41613Sbill 4172395Swnj tp = &dh11[unit]; 4182479Swnj addr = (struct dhdevice *)tp->t_addr; 4192468Swnj /* 4202468Swnj * Block interrupts so parameters will be set 4212468Swnj * before the line interrupts. 4222468Swnj */ 423300Sbill s = spl5(); 4242468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 42513Sbill if ((tp->t_ispeed)==0) { 42613Sbill tp->t_state |= HUPCLS; 4272479Swnj dmctl(unit, DML_OFF, DMSET); 42813Sbill return; 42913Sbill } 4302395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4312468Swnj if ((tp->t_ispeed) == B134) 4322395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4332312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4342395Swnj lpar |= BITS8; 43513Sbill else 4362395Swnj lpar |= BITS7|PENABLE; 43713Sbill if ((tp->t_flags&EVENP) == 0) 4382395Swnj lpar |= OPAR; 4392468Swnj if ((tp->t_ospeed) == B110) 4402395Swnj lpar |= TWOSB; 4412395Swnj addr->dhlpr = lpar; 442300Sbill splx(s); 44313Sbill } 44413Sbill 44513Sbill /* 44613Sbill * DH11 transmitter interrupt. 44713Sbill * Restart each line which used to be active but has 44813Sbill * terminated transmission since the last interrupt. 44913Sbill */ 4502395Swnj dhxint(dh) 4512395Swnj int dh; 45213Sbill { 45313Sbill register struct tty *tp; 4542479Swnj register struct dhdevice *addr; 45513Sbill short ttybit, bar, *sbar; 4562974Swnj register struct uba_device *ui; 4572468Swnj register int unit; 4582605Swnj u_short cntr; 45913Sbill 4602395Swnj ui = dhinfo[dh]; 4612479Swnj addr = (struct dhdevice *)ui->ui_addr; 4622456Swnj if (addr->un.dhcsr & DH_NXM) { 4632456Swnj addr->un.dhcsr |= DH_CNI; 4642924Swnj printf("dh%d: NXM\n", dh); 465105Sbill } 4662395Swnj sbar = &dhsar[dh]; 46713Sbill bar = *sbar & ~addr->dhbar; 4682395Swnj unit = dh * 16; ttybit = 1; 4692468Swnj addr->un.dhcsr &= (short)~DH_TI; 4702468Swnj for (; bar; unit++, ttybit <<= 1) { 4712468Swnj if (bar & ttybit) { 47213Sbill *sbar &= ~ttybit; 47313Sbill bar &= ~ttybit; 4742395Swnj tp = &dh11[unit]; 475113Sbill tp->t_state &= ~BUSY; 476113Sbill if (tp->t_state&FLUSH) 477113Sbill tp->t_state &= ~FLUSH; 478113Sbill else { 4792456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4802468Swnj /* 4812468Swnj * Do arithmetic in a short to make up 4822468Swnj * for lost 16&17 bits. 4832468Swnj */ 4842605Swnj cntr = addr->dhcar - 4852468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4863101Swnj ndflush(&tp->t_outq, (int)cntr); 487113Sbill } 488113Sbill if (tp->t_line) 48913Sbill (*linesw[tp->t_line].l_start)(tp); 490113Sbill else 49113Sbill dhstart(tp); 49213Sbill } 49313Sbill } 49413Sbill } 49513Sbill 49613Sbill /* 49713Sbill * Start (restart) transmission on the given DH11 line. 49813Sbill */ 49913Sbill dhstart(tp) 5002395Swnj register struct tty *tp; 50113Sbill { 5022479Swnj register struct dhdevice *addr; 5032468Swnj register int car, dh, unit, nch; 5042395Swnj int s; 50513Sbill 5062468Swnj unit = minor(tp->t_dev); 5072468Swnj dh = unit >> 4; 5082468Swnj unit &= 0xf; 5092479Swnj addr = (struct dhdevice *)tp->t_addr; 5102468Swnj 51113Sbill /* 5122468Swnj * Must hold interrupts in following code to prevent 5132468Swnj * state of the tp from changing. 51413Sbill */ 51513Sbill s = spl5(); 5162468Swnj /* 5172468Swnj * If it's currently active, or delaying, no need to do anything. 5182468Swnj */ 51913Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 52013Sbill goto out; 5212468Swnj /* 5222468Swnj * If there are sleepers, and output has drained below low 5232468Swnj * water mark, wake up the sleepers. 5242468Swnj */ 5252395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 52613Sbill tp->t_state &= ~ASLEEP; 5274831Swnj wakeup((caddr_t)&tp->t_outq); 52813Sbill } 5292468Swnj /* 5302468Swnj * Now restart transmission unless the output queue is 5312468Swnj * empty. 5322468Swnj */ 53313Sbill if (tp->t_outq.c_cc == 0) 53413Sbill goto out; 5353703Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 53613Sbill nch = ndqb(&tp->t_outq, 0); 5372395Swnj else { 53813Sbill nch = ndqb(&tp->t_outq, 0200); 5392468Swnj /* 5402468Swnj * If first thing on queue is a delay process it. 5412468Swnj */ 54213Sbill if (nch == 0) { 54313Sbill nch = getc(&tp->t_outq); 5442468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 54513Sbill tp->t_state |= TIMEOUT; 54613Sbill goto out; 54713Sbill } 54813Sbill } 5492468Swnj /* 5502468Swnj * If characters to transmit, restart transmission. 5512468Swnj */ 55213Sbill if (nch) { 5532468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5542468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5553586Sroot /* 5563586Sroot * The following nonsense with short word 5573586Sroot * is to make sure the dhbar |= word below 5583586Sroot * is done with an interlocking bisw2 instruction. 5593586Sroot */ 5603586Sroot { short word = 1 << unit; 5613586Sroot dhsar[dh] |= word; 5622468Swnj addr->dhcar = car; 56313Sbill addr->dhbcr = -nch; 5643586Sroot addr->dhbar |= word; 5653586Sroot } 56613Sbill tp->t_state |= BUSY; 56713Sbill } 5682395Swnj out: 56913Sbill splx(s); 57013Sbill } 57113Sbill 57213Sbill /* 5732468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 57413Sbill */ 57513Sbill /*ARGSUSED*/ 57613Sbill dhstop(tp, flag) 5772468Swnj register struct tty *tp; 57813Sbill { 5792479Swnj register struct dhdevice *addr; 5802395Swnj register int unit, s; 58113Sbill 5822479Swnj addr = (struct dhdevice *)tp->t_addr; 5832468Swnj /* 5842468Swnj * Block input/output interrupts while messing with state. 5852468Swnj */ 5862468Swnj s = spl5(); 587113Sbill if (tp->t_state & BUSY) { 5882468Swnj /* 5892468Swnj * Device is transmitting; stop output 5902468Swnj * by selecting the line and setting the byte 5912468Swnj * count to -1. We will clean up later 5922468Swnj * by examining the address where the dh stopped. 5932468Swnj */ 5942395Swnj unit = minor(tp->t_dev); 5952456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 59613Sbill if ((tp->t_state&TTSTOP)==0) 59713Sbill tp->t_state |= FLUSH; 598113Sbill addr->dhbcr = -1; 599113Sbill } 60013Sbill splx(s); 60113Sbill } 60213Sbill 603168Sbill /* 604280Sbill * Reset state of driver if UBA reset was necessary. 605280Sbill * Reset the csrl and lpr registers on open lines, and 606280Sbill * restart transmitters. 607280Sbill */ 6082395Swnj dhreset(uban) 6092468Swnj int uban; 610280Sbill { 6112395Swnj register int dh, unit; 612280Sbill register struct tty *tp; 6132974Swnj register struct uba_device *ui; 6142421Skre int i; 615280Sbill 6162421Skre if (dh_ubinfo[uban] == 0) 6172421Skre return; 6182421Skre ubarelse(uban, &dh_ubinfo[uban]); 6192421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6202770Swnj 512+nclist*sizeof (struct cblock), 0); 6212421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6222395Swnj dh = 0; 6232643Swnj for (dh = 0; dh < NDH; dh++) { 6242421Skre ui = dhinfo[dh]; 6252421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6262421Skre continue; 6272924Swnj printf(" dh%d", dh); 6282479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6292479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6302421Skre unit = dh * 16; 6312421Skre for (i = 0; i < 16; i++) { 6322421Skre tp = &dh11[unit]; 6332421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 6342421Skre dhparam(unit); 6352479Swnj dmctl(unit, DML_ON, DMSET); 6362421Skre tp->t_state &= ~BUSY; 6372421Skre dhstart(tp); 6382421Skre } 6392421Skre unit++; 640300Sbill } 641300Sbill } 642300Sbill dhtimer(); 643280Sbill } 6442395Swnj 6452468Swnj /* 6462468Swnj * At software clock interrupt time or after a UNIBUS reset 6472468Swnj * empty all the dh silos. 6482468Swnj */ 6492456Swnj dhtimer() 6502456Swnj { 6512456Swnj register int dh; 6522456Swnj 6532643Swnj for (dh = 0; dh < NDH; dh++) 6542456Swnj dhrint(dh); 6552456Swnj } 6562456Swnj 6572468Swnj /* 6582479Swnj * Turn on the line associated with dh dev. 6592468Swnj */ 6602468Swnj dmopen(dev) 6612468Swnj dev_t dev; 6622468Swnj { 6632468Swnj register struct tty *tp; 6642468Swnj register struct dmdevice *addr; 6652974Swnj register struct uba_device *ui; 6662468Swnj register int unit; 6672468Swnj register int dm; 6683792Swnj int s; 6692468Swnj 6702468Swnj unit = minor(dev); 6712479Swnj dm = unit >> 4; 6722468Swnj tp = &dh11[unit]; 6732566Swnj unit &= 0xf; 6742643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 6752566Swnj (dhsoftCAR[dm]&(1<<unit))) { 6762468Swnj tp->t_state |= CARR_ON; 6772468Swnj return; 6782468Swnj } 6792468Swnj addr = (struct dmdevice *)ui->ui_addr; 6803792Swnj s = spl5(); 6812479Swnj addr->dmcsr &= ~DM_SE; 6822479Swnj while (addr->dmcsr & DM_BUSY) 6832468Swnj ; 6842566Swnj addr->dmcsr = unit; 6852479Swnj addr->dmlstat = DML_ON; 6862479Swnj if (addr->dmlstat&DML_CAR) 6872468Swnj tp->t_state |= CARR_ON; 6883792Swnj addr->dmcsr = DM_IE|DM_SE; 6892468Swnj while ((tp->t_state&CARR_ON)==0) 6902468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6913792Swnj splx(s); 6922468Swnj } 6932468Swnj 6942468Swnj /* 6952468Swnj * Dump control bits into the DM registers. 6962468Swnj */ 6972468Swnj dmctl(dev, bits, how) 6982468Swnj dev_t dev; 6992468Swnj int bits, how; 7002468Swnj { 7012974Swnj register struct uba_device *ui; 7022468Swnj register struct dmdevice *addr; 7032468Swnj register int unit, s; 7042468Swnj int dm; 7052468Swnj 7062468Swnj unit = minor(dev); 7072468Swnj dm = unit >> 4; 7082468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7092468Swnj return; 7102468Swnj addr = (struct dmdevice *)ui->ui_addr; 7112468Swnj s = spl5(); 7122479Swnj addr->dmcsr &= ~DM_SE; 7132479Swnj while (addr->dmcsr & DM_BUSY) 7142468Swnj ; 7152468Swnj addr->dmcsr = unit & 0xf; 7162468Swnj switch(how) { 7172468Swnj case DMSET: 7182468Swnj addr->dmlstat = bits; 7192468Swnj break; 7202468Swnj case DMBIS: 7212468Swnj addr->dmlstat |= bits; 7222468Swnj break; 7232468Swnj case DMBIC: 7242468Swnj addr->dmlstat &= ~bits; 7252468Swnj break; 7262468Swnj } 7273792Swnj addr->dmcsr = DM_IE|DM_SE; 7282468Swnj splx(s); 7292468Swnj } 7302468Swnj 7312468Swnj /* 7322468Swnj * DM11 interrupt; deal with carrier transitions. 7332468Swnj */ 7342468Swnj dmintr(dm) 7352468Swnj register int dm; 7362468Swnj { 7372974Swnj register struct uba_device *ui; 7382468Swnj register struct tty *tp; 7392468Swnj register struct dmdevice *addr; 7402468Swnj 7412468Swnj ui = dminfo[dm]; 7422479Swnj if (ui == 0) 7432479Swnj return; 7442468Swnj addr = (struct dmdevice *)ui->ui_addr; 7453997Sroot if (addr->dmcsr&DM_DONE) { 7463997Sroot if (addr->dmcsr&DM_CF) { 7473997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7483997Sroot wakeup((caddr_t)&tp->t_rawq); 7492468Swnj if ((tp->t_state&WOPEN)==0 && 7503997Sroot (tp->t_local&LMDMBUF)) { 7513997Sroot if (addr->dmlstat & DML_CAR) { 7523997Sroot tp->t_state &= ~TTSTOP; 7533997Sroot ttstart(tp); 7543997Sroot } else if ((tp->t_state&TTSTOP) == 0) { 7553997Sroot tp->t_state |= TTSTOP; 7563997Sroot dhstop(tp, 0); 7573997Sroot } 7583997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7593997Sroot if ((tp->t_state&WOPEN)==0 && 7603997Sroot (tp->t_local&LNOHANG)==0) { 7613997Sroot gsignal(tp->t_pgrp, SIGHUP); 7623997Sroot gsignal(tp->t_pgrp, SIGCONT); 7633997Sroot addr->dmlstat = 0; 7643997Sroot flushtty(tp, FREAD|FWRITE); 7653997Sroot } 7663997Sroot tp->t_state &= ~CARR_ON; 7673997Sroot } else 7683997Sroot tp->t_state |= CARR_ON; 7693997Sroot } 7703997Sroot addr->dmcsr = DM_IE|DM_SE; 7712468Swnj } 7722468Swnj } 7732625Swnj #endif 774