1*2566Swnj /* dh.c 4.19 81/02/19 */ 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" 17*2566Swnj #include "../h/vm.h" 1813Sbill #include "../h/uba.h" 19113Sbill #include "../h/bk.h" 201561Sbill #include "../h/clist.h" 211786Sbill #include "../h/mx.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 */ 282395Swnj int dhcntrlr(), dhslave(), dhrint(), dhxint(); 292395Swnj struct uba_dinfo *dhinfo[NDH11]; 302395Swnj u_short dhstd[] = { 0 }; 312395Swnj struct uba_driver dhdriver = 32*2566Swnj { dhcntrlr, dhslave, 0, 0, dhstd, "dh", dhinfo }; 332395Swnj 342479Swnj int dmcntrlr(), dmslave(), dmintr(); 352479Swnj struct uba_dinfo *dminfo[NDH11]; 362479Swnj u_short dmstd[] = { 0 }; 372479Swnj struct uba_driver dmdriver = 38*2566Swnj { dmcntrlr, dmslave, 0, 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 1152479Swnj #define DML_ON (DML_DTR|DML_LE) 1162479Swnj #define DML_OFF (DML_LE) 1172479Swnj 11813Sbill /* 1192479Swnj * Local variables for the driver 12013Sbill */ 1212479Swnj short dhsar[NDH11]; /* software copy of last bar */ 122*2566Swnj short dhsoftCAR[NDH11]; 12313Sbill 1242479Swnj struct tty dh11[NDH11*16]; 1252479Swnj int ndh11 = NDH11*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*/ 1432395Swnj dhcntrlr(ui, reg) 1442395Swnj struct uba_dinfo *ui; 1452395Swnj caddr_t reg; 1462395Swnj { 1472468Swnj register int br, cvec; /* these are ``value-result'' */ 1482479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1492421Skre int i; 1502395Swnj 151*2566Swnj #ifdef notdef 152*2566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 153*2566Swnj DELAY(5); 154*2566Swnj dhaddr->un.dhcsr = 0; 155*2566Swnj #else 1562456Swnj dhaddr->un.dhcsr = DH_TIE; 1572456Swnj DELAY(5); 1582456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1592421Skre dhaddr->dhbcr = -1; 1602456Swnj dhaddr->dhcar = 0; 1612421Skre dhaddr->dhbar = 1; 1622456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1632421Skre dhaddr->un.dhcsr = 0; 1642456Swnj if (cvec && cvec != 0x200) 1652456Swnj cvec -= 4; /* transmit -> receive */ 1662482Swnj #endif 1672456Swnj return (1); 1682395Swnj } 1692395Swnj 1702456Swnj /* 1712456Swnj * Routine called to init slave tables. 1722456Swnj */ 173*2566Swnj dhslave(ui, reg) 1742395Swnj struct uba_dinfo *ui; 1752395Swnj caddr_t reg; 1762395Swnj { 1772395Swnj 178*2566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1792395Swnj } 1802395Swnj 18113Sbill /* 1822479Swnj * Configuration routine to cause a dm to interrupt. 1832479Swnj */ 1842479Swnj dmcntrlr(um, addr) 1852479Swnj struct uba_minfo *um; 1862479Swnj caddr_t addr; 1872479Swnj { 1882479Swnj register int br, vec; /* value-result */ 1892479Swnj register struct dmdevice *dmaddr = (struct dmdevice *)addr; 1902479Swnj 1912479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1922479Swnj DELAY(20); 1932479Swnj dmaddr->dmcsr = 0; 1942479Swnj } 1952479Swnj 1962479Swnj dmslave(ui, addr, slave) 1972479Swnj struct uba_dinfo *ui; 1982479Swnj caddr_t addr; 1992479Swnj int slave; 2002479Swnj { 2012479Swnj 2022479Swnj /* no local state to set up */ 2032479Swnj } 2042479Swnj 2052479Swnj /* 2062468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2072468Swnj * is the first dh on this uba. Turn on this dh if this is 2082468Swnj * the first use of it. Also do a dmopen to wait for carrier. 20913Sbill */ 21013Sbill /*ARGSUSED*/ 21113Sbill dhopen(dev, flag) 2122395Swnj dev_t dev; 21313Sbill { 21413Sbill register struct tty *tp; 2152395Swnj register int unit, dh; 2162479Swnj register struct dhdevice *addr; 2172395Swnj register struct uba_dinfo *ui; 21813Sbill int s; 21913Sbill 2202395Swnj unit = minor(dev); 2212395Swnj dh = unit >> 4; 2222468Swnj if (unit >= NDH11*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 22313Sbill u.u_error = ENXIO; 22413Sbill return; 22513Sbill } 2262395Swnj tp = &dh11[unit]; 2272468Swnj if (tp->t_state&XCLUDE && u.u_uid!=0) { 2282468Swnj u.u_error = EBUSY; 2292468Swnj return; 2302468Swnj } 2312479Swnj addr = (struct dhdevice *)ui->ui_addr; 23213Sbill tp->t_addr = (caddr_t)addr; 23313Sbill tp->t_oproc = dhstart; 23413Sbill tp->t_iproc = NULL; 23513Sbill tp->t_state |= WOPEN; 2362468Swnj /* 2372468Swnj * While setting up state for this uba and this dh, 2382468Swnj * block uba resets which can clear the state. 2392468Swnj */ 2402468Swnj s = spl5(); 2412421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 242717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2432395Swnj dh_ubinfo[ui->ui_ubanum] = 2442421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2452395Swnj 512+NCLIST*sizeof(struct cblock), 0); 2462456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 24713Sbill } 2482456Swnj if ((dhact&(1<<dh)) == 0) { 2492456Swnj addr->un.dhcsr |= DH_IE; 2502468Swnj DELAY(5); 2512468Swnj dhact |= (1<<dh); 2522456Swnj addr->dhsilo = 16; 2532456Swnj } 25413Sbill splx(s); 2552468Swnj /* 2562468Swnj * If this is first open, initialze tty state to default. 2572468Swnj */ 25813Sbill if ((tp->t_state&ISOPEN) == 0) { 25913Sbill ttychars(tp); 260168Sbill if (tp->t_ispeed == 0) { 2612456Swnj tp->t_ispeed = B300; 2622456Swnj tp->t_ospeed = B300; 263168Sbill tp->t_flags = ODDP|EVENP|ECHO; 264168Sbill } 2652395Swnj dhparam(unit); 26613Sbill } 2672468Swnj /* 2682468Swnj * Wait for carrier, then process line discipline specific open. 2692468Swnj */ 27013Sbill dmopen(dev); 2712395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 27213Sbill } 27313Sbill 27413Sbill /* 2752468Swnj * Close a DH11 line, turning off the DM11. 27613Sbill */ 27713Sbill /*ARGSUSED*/ 27813Sbill dhclose(dev, flag) 2792395Swnj dev_t dev; 2802395Swnj int flag; 28113Sbill { 28213Sbill register struct tty *tp; 2832395Swnj register unit; 28413Sbill 2852395Swnj unit = minor(dev); 2862395Swnj tp = &dh11[unit]; 28713Sbill (*linesw[tp->t_line].l_close)(tp); 2882479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 28913Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 2902479Swnj dmctl(unit, DML_OFF, DMSET); 29113Sbill ttyclose(tp); 29213Sbill } 29313Sbill 29413Sbill dhread(dev) 2952395Swnj dev_t dev; 29613Sbill { 2972395Swnj register struct tty *tp; 29813Sbill 2992395Swnj tp = &dh11[minor(dev)]; 30013Sbill (*linesw[tp->t_line].l_read)(tp); 30113Sbill } 30213Sbill 30313Sbill dhwrite(dev) 3042395Swnj dev_t dev; 30513Sbill { 3062395Swnj register struct tty *tp; 30713Sbill 3082395Swnj tp = &dh11[minor(dev)]; 30913Sbill (*linesw[tp->t_line].l_write)(tp); 31013Sbill } 31113Sbill 31213Sbill /* 31313Sbill * DH11 receiver interrupt. 31413Sbill */ 3152395Swnj dhrint(dh) 3162395Swnj int dh; 31713Sbill { 31813Sbill register struct tty *tp; 3192395Swnj register c; 3202479Swnj register struct dhdevice *addr; 321117Sbill register struct tty *tp0; 3222395Swnj register struct uba_dinfo *ui; 323139Sbill int s; 32413Sbill 3252395Swnj ui = dhinfo[dh]; 3262479Swnj if (ui == 0 || ui->ui_alive == 0) 3272479Swnj return; 3282479Swnj addr = (struct dhdevice *)ui->ui_addr; 3292468Swnj tp0 = &dh11[dh<<4]; 3302468Swnj /* 3312468Swnj * Loop fetching characters from the silo for this 3322468Swnj * dh until there are no more in the silo. 3332468Swnj */ 3342468Swnj while ((c = addr->dhrcr) < 0) { 3352468Swnj tp = tp0 + ((c>>8)&0xf); 3362468Swnj if ((tp->t_state&ISOPEN)==0) { 33713Sbill wakeup((caddr_t)tp); 33813Sbill continue; 33913Sbill } 3402468Swnj if (c & DH_PE) 34113Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 34213Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 34313Sbill continue; 3442468Swnj if (c & DH_DO) 34513Sbill printf("O"); 3462468Swnj if (c & DH_FE) 3472468Swnj /* 3482468Swnj * At framing error (break) generate 3492468Swnj * a null (in raw mode, for getty), or a 3502468Swnj * interrupt (in cooked/cbreak mode). 3512468Swnj */ 35213Sbill if (tp->t_flags&RAW) 3532468Swnj c = 0; 35413Sbill else 355184Sbill c = tun.t_intrc; 356139Sbill if (tp->t_line == NETLDISC) { 357117Sbill c &= 0177; 358168Sbill BKINPUT(c, tp); 359117Sbill } else 3602468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 36113Sbill } 36213Sbill } 36313Sbill 36413Sbill /* 3652468Swnj * Ioctl for DH11. 36613Sbill */ 36713Sbill /*ARGSUSED*/ 36813Sbill dhioctl(dev, cmd, addr, flag) 3692395Swnj caddr_t addr; 37013Sbill { 37113Sbill register struct tty *tp; 3722395Swnj register unit = minor(dev); 37313Sbill 3742395Swnj tp = &dh11[unit]; 375113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 3762468Swnj if (cmd == 0) 377113Sbill return; 3781895Swnj if (ttioctl(tp, cmd, addr, flag)) { 3792468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 3802395Swnj dhparam(unit); 381168Sbill } else switch(cmd) { 382168Sbill case TIOCSBRK: 3832479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 384168Sbill break; 385168Sbill case TIOCCBRK: 3862479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 387168Sbill break; 388168Sbill case TIOCSDTR: 3892479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 390168Sbill break; 391168Sbill case TIOCCDTR: 3922479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 393168Sbill break; 394168Sbill default: 39513Sbill u.u_error = ENOTTY; 396168Sbill } 39713Sbill } 39813Sbill 39913Sbill /* 40013Sbill * Set parameters from open or stty into the DH hardware 40113Sbill * registers. 40213Sbill */ 4032395Swnj dhparam(unit) 4042395Swnj register int unit; 40513Sbill { 40613Sbill register struct tty *tp; 4072479Swnj register struct dhdevice *addr; 4082395Swnj register int lpar; 409300Sbill int s; 41013Sbill 4112395Swnj tp = &dh11[unit]; 4122479Swnj addr = (struct dhdevice *)tp->t_addr; 4132468Swnj /* 4142468Swnj * Block interrupts so parameters will be set 4152468Swnj * before the line interrupts. 4162468Swnj */ 417300Sbill s = spl5(); 4182468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 41913Sbill if ((tp->t_ispeed)==0) { 42013Sbill tp->t_state |= HUPCLS; 4212479Swnj dmctl(unit, DML_OFF, DMSET); 42213Sbill return; 42313Sbill } 4242395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4252468Swnj if ((tp->t_ispeed) == B134) 4262395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4272312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4282395Swnj lpar |= BITS8; 42913Sbill else 4302395Swnj lpar |= BITS7|PENABLE; 43113Sbill if ((tp->t_flags&EVENP) == 0) 4322395Swnj lpar |= OPAR; 4332468Swnj if ((tp->t_ospeed) == B110) 4342395Swnj lpar |= TWOSB; 4352395Swnj addr->dhlpr = lpar; 436300Sbill splx(s); 43713Sbill } 43813Sbill 43913Sbill /* 44013Sbill * DH11 transmitter interrupt. 44113Sbill * Restart each line which used to be active but has 44213Sbill * terminated transmission since the last interrupt. 44313Sbill */ 4442395Swnj dhxint(dh) 4452395Swnj int dh; 44613Sbill { 44713Sbill register struct tty *tp; 4482479Swnj register struct dhdevice *addr; 44913Sbill short ttybit, bar, *sbar; 4502395Swnj register struct uba_dinfo *ui; 4512468Swnj register int unit; 452144Sbill int s; 4532468Swnj u_short cnt; 45413Sbill 4552395Swnj ui = dhinfo[dh]; 4562479Swnj addr = (struct dhdevice *)ui->ui_addr; 4572456Swnj if (addr->un.dhcsr & DH_NXM) { 4582468Swnj DELAY(5); 4592456Swnj addr->un.dhcsr |= DH_CNI; 4602468Swnj printf("dh%d NXM\n", dh); 461105Sbill } 4622395Swnj sbar = &dhsar[dh]; 46313Sbill bar = *sbar & ~addr->dhbar; 4642395Swnj unit = dh * 16; ttybit = 1; 4652468Swnj addr->un.dhcsr &= (short)~DH_TI; 4662468Swnj for (; bar; unit++, ttybit <<= 1) { 4672468Swnj if (bar & ttybit) { 46813Sbill *sbar &= ~ttybit; 46913Sbill bar &= ~ttybit; 4702395Swnj tp = &dh11[unit]; 471113Sbill tp->t_state &= ~BUSY; 472113Sbill if (tp->t_state&FLUSH) 473113Sbill tp->t_state &= ~FLUSH; 474113Sbill else { 4752456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4762468Swnj DELAY(5); 4772468Swnj /* 4782468Swnj * Do arithmetic in a short to make up 4792468Swnj * for lost 16&17 bits. 4802468Swnj */ 4812468Swnj cnt = addr->dhcar - 4822468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4832468Swnj ndflush(&tp->t_outq, cnt); 484113Sbill } 485113Sbill if (tp->t_line) 48613Sbill (*linesw[tp->t_line].l_start)(tp); 487113Sbill else 48813Sbill dhstart(tp); 48913Sbill } 49013Sbill } 49113Sbill } 49213Sbill 49313Sbill /* 49413Sbill * Start (restart) transmission on the given DH11 line. 49513Sbill */ 49613Sbill dhstart(tp) 4972395Swnj register struct tty *tp; 49813Sbill { 4992479Swnj register struct dhdevice *addr; 5002468Swnj register int car, dh, unit, nch; 5012395Swnj int s; 50213Sbill 5032468Swnj unit = minor(tp->t_dev); 5042468Swnj dh = unit >> 4; 5052468Swnj unit &= 0xf; 5062479Swnj addr = (struct dhdevice *)tp->t_addr; 5072468Swnj 50813Sbill /* 5092468Swnj * Must hold interrupts in following code to prevent 5102468Swnj * state of the tp from changing. 51113Sbill */ 51213Sbill s = spl5(); 5132468Swnj /* 5142468Swnj * If it's currently active, or delaying, no need to do anything. 5152468Swnj */ 51613Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 51713Sbill goto out; 5182468Swnj /* 5192468Swnj * If there are sleepers, and output has drained below low 5202468Swnj * water mark, wake up the sleepers. 5212468Swnj */ 5222395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 52313Sbill tp->t_state &= ~ASLEEP; 52413Sbill if (tp->t_chan) 525168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 526168Sbill else 52713Sbill 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; 5352395Swnj if (tp->t_flags & RAW) 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; 5552468Swnj DELAY(5); 5562468Swnj unit = 1 << unit; 5572468Swnj dhsar[dh] |= unit; 5582468Swnj addr->dhcar = car; 55913Sbill addr->dhbcr = -nch; 5602468Swnj addr->dhbar |= unit; 56113Sbill tp->t_state |= BUSY; 56213Sbill } 5632395Swnj out: 56413Sbill splx(s); 56513Sbill } 56613Sbill 56713Sbill /* 5682468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 56913Sbill */ 57013Sbill /*ARGSUSED*/ 57113Sbill dhstop(tp, flag) 5722468Swnj register struct tty *tp; 57313Sbill { 5742479Swnj register struct dhdevice *addr; 5752395Swnj register int unit, s; 57613Sbill 5772479Swnj addr = (struct dhdevice *)tp->t_addr; 5782468Swnj /* 5792468Swnj * Block input/output interrupts while messing with state. 5802468Swnj */ 5812468Swnj s = spl5(); 582113Sbill if (tp->t_state & BUSY) { 5832468Swnj /* 5842468Swnj * Device is transmitting; stop output 5852468Swnj * by selecting the line and setting the byte 5862468Swnj * count to -1. We will clean up later 5872468Swnj * by examining the address where the dh stopped. 5882468Swnj */ 5892395Swnj unit = minor(tp->t_dev); 5902456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5912468Swnj DELAY(5); 59213Sbill if ((tp->t_state&TTSTOP)==0) 59313Sbill tp->t_state |= FLUSH; 594113Sbill addr->dhbcr = -1; 595113Sbill } 59613Sbill splx(s); 59713Sbill } 59813Sbill 599168Sbill /* 600280Sbill * Reset state of driver if UBA reset was necessary. 601280Sbill * Reset the csrl and lpr registers on open lines, and 602280Sbill * restart transmitters. 603280Sbill */ 6042395Swnj dhreset(uban) 6052468Swnj int uban; 606280Sbill { 6072395Swnj register int dh, unit; 608280Sbill register struct tty *tp; 6092395Swnj register struct uba_dinfo *ui; 6102421Skre int i; 611280Sbill 6122421Skre if (dh_ubinfo[uban] == 0) 6132421Skre return; 614280Sbill printf(" dh"); 6152421Skre ubarelse(uban, &dh_ubinfo[uban]); 6162421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6172421Skre 512+NCLIST*sizeof (struct cblock), 0); 6182421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6192395Swnj dh = 0; 6202421Skre for (dh = 0; dh < NDH11; dh++) { 6212421Skre ui = dhinfo[dh]; 6222421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6232421Skre continue; 6242479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6252468Swnj DELAY(5); 6262479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6272421Skre unit = dh * 16; 6282421Skre for (i = 0; i < 16; i++) { 6292421Skre tp = &dh11[unit]; 6302421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 6312421Skre dhparam(unit); 6322479Swnj dmctl(unit, DML_ON, DMSET); 6332421Skre tp->t_state &= ~BUSY; 6342421Skre dhstart(tp); 6352421Skre } 6362421Skre unit++; 637300Sbill } 638300Sbill } 639300Sbill dhtimer(); 640280Sbill } 6412395Swnj 6422468Swnj /* 6432468Swnj * At software clock interrupt time or after a UNIBUS reset 6442468Swnj * empty all the dh silos. 6452468Swnj */ 6462456Swnj dhtimer() 6472456Swnj { 6482456Swnj register int dh; 6492456Swnj 6502456Swnj for (dh = 0; dh < NDH11; dh++) 6512456Swnj dhrint(dh); 6522456Swnj } 6532456Swnj 6542468Swnj /* 6552479Swnj * Turn on the line associated with dh dev. 6562468Swnj */ 6572468Swnj dmopen(dev) 6582468Swnj dev_t dev; 6592468Swnj { 6602468Swnj register struct tty *tp; 6612468Swnj register struct dmdevice *addr; 6622468Swnj register struct uba_dinfo *ui; 6632468Swnj register int unit; 6642468Swnj register int dm; 6652468Swnj 6662468Swnj unit = minor(dev); 6672479Swnj dm = unit >> 4; 6682468Swnj tp = &dh11[unit]; 669*2566Swnj unit &= 0xf; 670*2566Swnj if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 671*2566Swnj (dhsoftCAR[dm]&(1<<unit))) { 6722468Swnj tp->t_state |= CARR_ON; 6732468Swnj return; 6742468Swnj } 6752468Swnj addr = (struct dmdevice *)ui->ui_addr; 6762468Swnj spl5(); 6772479Swnj addr->dmcsr &= ~DM_SE; 6782479Swnj while (addr->dmcsr & DM_BUSY) 6792468Swnj ; 680*2566Swnj addr->dmcsr = unit; 6812479Swnj addr->dmlstat = DML_ON; 6822479Swnj if (addr->dmlstat&DML_CAR) 6832468Swnj tp->t_state |= CARR_ON; 6842479Swnj addr->dmcsr = DH_IE|DM_SE; 6852468Swnj while ((tp->t_state&CARR_ON)==0) 6862468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6872468Swnj spl0(); 6882468Swnj } 6892468Swnj 6902468Swnj /* 6912468Swnj * Dump control bits into the DM registers. 6922468Swnj */ 6932468Swnj dmctl(dev, bits, how) 6942468Swnj dev_t dev; 6952468Swnj int bits, how; 6962468Swnj { 6972468Swnj register struct uba_dinfo *ui; 6982468Swnj register struct dmdevice *addr; 6992468Swnj register int unit, s; 7002468Swnj int dm; 7012468Swnj 7022468Swnj unit = minor(dev); 7032468Swnj dm = unit >> 4; 7042468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7052468Swnj return; 7062468Swnj addr = (struct dmdevice *)ui->ui_addr; 7072468Swnj s = spl5(); 7082479Swnj addr->dmcsr &= ~DM_SE; 7092479Swnj while (addr->dmcsr & DM_BUSY) 7102468Swnj ; 7112468Swnj addr->dmcsr = unit & 0xf; 7122468Swnj switch(how) { 7132468Swnj case DMSET: 7142468Swnj addr->dmlstat = bits; 7152468Swnj break; 7162468Swnj case DMBIS: 7172468Swnj addr->dmlstat |= bits; 7182468Swnj break; 7192468Swnj case DMBIC: 7202468Swnj addr->dmlstat &= ~bits; 7212468Swnj break; 7222468Swnj } 7232479Swnj addr->dmcsr = DH_IE|DM_SE; 7242468Swnj splx(s); 7252468Swnj } 7262468Swnj 7272468Swnj /* 7282468Swnj * DM11 interrupt; deal with carrier transitions. 7292468Swnj */ 7302468Swnj dmintr(dm) 7312468Swnj register int dm; 7322468Swnj { 7332468Swnj register struct uba_dinfo *ui; 7342468Swnj register struct tty *tp; 7352468Swnj register struct dmdevice *addr; 7362468Swnj 7372468Swnj ui = dminfo[dm]; 7382479Swnj if (ui == 0) 7392479Swnj return; 7402468Swnj addr = (struct dmdevice *)ui->ui_addr; 7412479Swnj if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CF) { 7422468Swnj tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7432468Swnj wakeup((caddr_t)&tp->t_rawq); 7442468Swnj if ((tp->t_state&WOPEN)==0 && 7452468Swnj (tp->t_local&LMDMBUF)) { 7462479Swnj if (addr->dmlstat & DML_CAR) { 7472468Swnj tp->t_state &= ~TTSTOP; 7482468Swnj ttstart(tp); 7492468Swnj } else if ((tp->t_state&TTSTOP) == 0) { 7502468Swnj tp->t_state |= TTSTOP; 7512468Swnj dhstop(tp, 0); 7522468Swnj } 7532479Swnj } else if ((addr->dmlstat&DML_CAR)==0) { 7542468Swnj if ((tp->t_state&WOPEN)==0 && 7552468Swnj (tp->t_local&LNOHANG)==0) { 7562468Swnj gsignal(tp->t_pgrp, SIGHUP); 7572468Swnj gsignal(tp->t_pgrp, SIGCONT); 7582468Swnj addr->dmlstat = 0; 7592468Swnj flushtty(tp, FREAD|FWRITE); 7602468Swnj } 7612468Swnj tp->t_state &= ~CARR_ON; 7622468Swnj } else 7632468Swnj tp->t_state |= CARR_ON; 7642479Swnj addr->dmcsr = DH_IE|DM_SE; 7652468Swnj } 7662468Swnj } 767