1*7725Sroot /* dh.c 4.48 82/08/13 */ 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" 136185Ssam #include "../h/proc.h" 1413Sbill #include "../h/tty.h" 1513Sbill #include "../h/map.h" 1613Sbill #include "../h/pte.h" 172395Swnj #include "../h/buf.h" 182566Swnj #include "../h/vm.h" 192974Swnj #include "../h/ubareg.h" 202974Swnj #include "../h/ubavar.h" 21113Sbill #include "../h/bk.h" 221561Sbill #include "../h/clist.h" 232468Swnj #include "../h/file.h" 24*7725Sroot #include "../h/uio.h" 2513Sbill 262468Swnj /* 272479Swnj * Definition of the driver for the auto-configuration program. 282479Swnj * There is one definition for the dh and one for the dm. 292468Swnj */ 302605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 312974Swnj struct uba_device *dhinfo[NDH]; 322395Swnj u_short dhstd[] = { 0 }; 332395Swnj struct uba_driver dhdriver = 342605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 352395Swnj 362605Swnj int dmprobe(), dmattach(), dmintr(); 372974Swnj struct uba_device *dminfo[NDH]; 382479Swnj u_short dmstd[] = { 0 }; 392479Swnj struct uba_driver dmdriver = 402605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4113Sbill 422479Swnj struct dhdevice 432479Swnj { 442479Swnj union { 452479Swnj short dhcsr; /* control-status register */ 462479Swnj char dhcsrl; /* low byte for line select */ 472479Swnj } un; 482479Swnj short dhrcr; /* receive character register */ 492479Swnj short dhlpr; /* line parameter register */ 502479Swnj u_short dhcar; /* current address register */ 512479Swnj short dhbcr; /* byte count register */ 522479Swnj u_short dhbar; /* buffer active register */ 532479Swnj short dhbreak; /* break control register */ 542479Swnj short dhsilo; /* silo status register */ 552479Swnj }; 5613Sbill 576615Ssam #ifndef PORTSELECTOR 586615Ssam #define ISPEED B300 596615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 606615Ssam #else 616615Ssam #define ISPEED B4800 626615Ssam #define IFLAGS (EVENP|ODDP) 636615Ssam #endif 646615Ssam 652456Swnj /* Bits in dhcsr */ 662456Swnj #define DH_TI 0100000 /* transmit interrupt */ 672456Swnj #define DH_SI 0040000 /* storage interrupt */ 682456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 692456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 702456Swnj #define DH_MC 0004000 /* master clear */ 712456Swnj #define DH_NXM 0002000 /* non-existant memory */ 722456Swnj #define DH_MM 0001000 /* maintenance mode */ 732456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 742456Swnj #define DH_RI 0000200 /* receiver interrupt */ 752456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 7613Sbill 772479Swnj /* Bits in dhlpr */ 782479Swnj #define BITS6 01 792479Swnj #define BITS7 02 802479Swnj #define BITS8 03 812479Swnj #define TWOSB 04 822479Swnj #define PENABLE 020 832479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 842479Swnj #define OPAR 040 852479Swnj #define HDUPLX 040000 862479Swnj 872456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 882456Swnj 892456Swnj /* Bits in dhrcr */ 902479Swnj #define DH_PE 0010000 /* parity error */ 912479Swnj #define DH_FE 0020000 /* framing error */ 922479Swnj #define DH_DO 0040000 /* data overrun */ 932456Swnj 942479Swnj struct dmdevice 952479Swnj { 962479Swnj short dmcsr; /* control status register */ 972479Swnj short dmlstat; /* line status register */ 982479Swnj short dmpad1[2]; 992479Swnj }; 1002479Swnj 1012479Swnj /* bits in dm csr */ 1022479Swnj #define DM_RF 0100000 /* ring flag */ 1032479Swnj #define DM_CF 0040000 /* carrier flag */ 1042479Swnj #define DM_CTS 0020000 /* clear to send */ 1052479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 1062479Swnj #define DM_CS 0004000 /* clear scan */ 1072479Swnj #define DM_CM 0002000 /* clear multiplexor */ 1082479Swnj #define DM_MM 0001000 /* maintenance mode */ 1092479Swnj #define DM_STP 0000400 /* step */ 1102479Swnj #define DM_DONE 0000200 /* scanner is done */ 1112479Swnj #define DM_IE 0000100 /* interrupt enable */ 1122479Swnj #define DM_SE 0000040 /* scan enable */ 1132479Swnj #define DM_BUSY 0000020 /* scan busy */ 1142479Swnj 1152479Swnj /* bits in dm lsr */ 1162479Swnj #define DML_RNG 0000200 /* ring */ 1172479Swnj #define DML_CAR 0000100 /* carrier detect */ 1182479Swnj #define DML_CTS 0000040 /* clear to send */ 1192479Swnj #define DML_SR 0000020 /* secondary receive */ 1202479Swnj #define DML_ST 0000010 /* secondary transmit */ 1212479Swnj #define DML_RTS 0000004 /* request to send */ 1222479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1232479Swnj #define DML_LE 0000001 /* line enable */ 1242479Swnj 1253792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1262479Swnj #define DML_OFF (DML_LE) 1272479Swnj 12813Sbill /* 1292479Swnj * Local variables for the driver 13013Sbill */ 1312643Swnj short dhsar[NDH]; /* software copy of last bar */ 1322643Swnj short dhsoftCAR[NDH]; 13313Sbill 1342643Swnj struct tty dh11[NDH*16]; 1352643Swnj int ndh11 = NDH*16; 1362479Swnj int dhact; /* mask of active dh's */ 1372479Swnj int dhstart(), ttrstrt(); 13813Sbill 1392479Swnj /* 1402479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1412479Swnj * The UBACVT macro converts a clist space address for unibus uban 1422479Swnj * into an i/o space address for the DMA routine. 1432479Swnj */ 1442479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1452479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1462479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 14713Sbill 1482456Swnj /* 1492456Swnj * Routine for configuration to force a dh to interrupt. 1502456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1512456Swnj */ 1522468Swnj /*ARGSUSED*/ 1532605Swnj dhprobe(reg) 1542395Swnj caddr_t reg; 1552395Swnj { 1562468Swnj register int br, cvec; /* these are ``value-result'' */ 1572479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1582395Swnj 1592605Swnj #ifdef lint 1602605Swnj br = 0; cvec = br; br = cvec; 1617384Sroot if (ndh11 == 0) ndh11 = 1; 1624932Swnj dhrint(0); dhxint(0); 1632605Swnj #endif 1642696Swnj #ifndef notdef 1652566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1666380Swnj DELAY(1000); 1677384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1682566Swnj dhaddr->un.dhcsr = 0; 1692566Swnj #else 1702456Swnj dhaddr->un.dhcsr = DH_TIE; 1712456Swnj DELAY(5); 1722456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1732421Skre dhaddr->dhbcr = -1; 1742456Swnj dhaddr->dhcar = 0; 1752421Skre dhaddr->dhbar = 1; 1762456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1772421Skre dhaddr->un.dhcsr = 0; 1782456Swnj if (cvec && cvec != 0x200) 1792456Swnj cvec -= 4; /* transmit -> receive */ 1802482Swnj #endif 1817408Skre return (sizeof (struct dhdevice)); 1822395Swnj } 1832395Swnj 1842456Swnj /* 1852605Swnj * Routine called to attach a dh. 1862456Swnj */ 1872605Swnj dhattach(ui) 1882974Swnj struct uba_device *ui; 1892395Swnj { 1902395Swnj 1912566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1922395Swnj } 1932395Swnj 19413Sbill /* 1952479Swnj * Configuration routine to cause a dm to interrupt. 1962479Swnj */ 1972605Swnj dmprobe(reg) 1982605Swnj caddr_t reg; 1992479Swnj { 2002479Swnj register int br, vec; /* value-result */ 2012605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 2022479Swnj 2032605Swnj #ifdef lint 2043101Swnj br = 0; vec = br; br = vec; 2056185Ssam dmintr(0); 2062605Swnj #endif 2072479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 2082479Swnj DELAY(20); 2092479Swnj dmaddr->dmcsr = 0; 2102605Swnj return (1); 2112479Swnj } 2122479Swnj 2132605Swnj /*ARGSUSED*/ 2142605Swnj dmattach(ui) 2152974Swnj struct uba_device *ui; 2162479Swnj { 2172479Swnj 2182479Swnj /* no local state to set up */ 2192479Swnj } 2202479Swnj 2212479Swnj /* 2222468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2232468Swnj * is the first dh on this uba. Turn on this dh if this is 2242468Swnj * the first use of it. Also do a dmopen to wait for carrier. 22513Sbill */ 22613Sbill /*ARGSUSED*/ 22713Sbill dhopen(dev, flag) 2282395Swnj dev_t dev; 22913Sbill { 23013Sbill register struct tty *tp; 2312395Swnj register int unit, dh; 2322479Swnj register struct dhdevice *addr; 2332974Swnj register struct uba_device *ui; 23413Sbill int s; 23513Sbill 2362395Swnj unit = minor(dev); 2372395Swnj dh = unit >> 4; 2382643Swnj if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 23913Sbill u.u_error = ENXIO; 24013Sbill return; 24113Sbill } 2422395Swnj tp = &dh11[unit]; 2435406Swnj if (tp->t_state&TS_XCLUDE && u.u_uid!=0) { 2442468Swnj u.u_error = EBUSY; 2452468Swnj return; 2462468Swnj } 2472479Swnj addr = (struct dhdevice *)ui->ui_addr; 24813Sbill tp->t_addr = (caddr_t)addr; 24913Sbill tp->t_oproc = dhstart; 2505406Swnj tp->t_state |= TS_WOPEN; 2512468Swnj /* 2522468Swnj * While setting up state for this uba and this dh, 2532468Swnj * block uba resets which can clear the state. 2542468Swnj */ 2552468Swnj s = spl5(); 2562421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 257717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2582395Swnj dh_ubinfo[ui->ui_ubanum] = 2592421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2602770Swnj 512+nclist*sizeof(struct cblock), 0); 2612456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 26213Sbill } 2632456Swnj if ((dhact&(1<<dh)) == 0) { 2642456Swnj addr->un.dhcsr |= DH_IE; 2652468Swnj dhact |= (1<<dh); 2662456Swnj addr->dhsilo = 16; 2672456Swnj } 26813Sbill splx(s); 2692468Swnj /* 2702468Swnj * If this is first open, initialze tty state to default. 2712468Swnj */ 2725406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 27313Sbill ttychars(tp); 2746615Ssam #ifndef PORTSELECTOR 275168Sbill if (tp->t_ispeed == 0) { 2766615Ssam #endif 2776615Ssam tp->t_ispeed = ISPEED; 2786615Ssam tp->t_ospeed = ISPEED; 2796615Ssam tp->t_flags = IFLAGS; 2806615Ssam #ifndef PORTSELECTOR 281168Sbill } 2826615Ssam #endif 2832395Swnj dhparam(unit); 28413Sbill } 2852468Swnj /* 2862468Swnj * Wait for carrier, then process line discipline specific open. 2872468Swnj */ 28813Sbill dmopen(dev); 2892395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 29013Sbill } 29113Sbill 29213Sbill /* 2932468Swnj * Close a DH11 line, turning off the DM11. 29413Sbill */ 29513Sbill /*ARGSUSED*/ 29613Sbill dhclose(dev, flag) 2972395Swnj dev_t dev; 2982395Swnj int flag; 29913Sbill { 30013Sbill register struct tty *tp; 3012395Swnj register unit; 30213Sbill 3032395Swnj unit = minor(dev); 3042395Swnj tp = &dh11[unit]; 30513Sbill (*linesw[tp->t_line].l_close)(tp); 3062479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 3075406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3082479Swnj dmctl(unit, DML_OFF, DMSET); 30913Sbill ttyclose(tp); 31013Sbill } 31113Sbill 312*7725Sroot dhread(dev, uio) 3132395Swnj dev_t dev; 314*7725Sroot struct uio *uio; 31513Sbill { 3162395Swnj register struct tty *tp; 31713Sbill 3182395Swnj tp = &dh11[minor(dev)]; 319*7725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 32013Sbill } 32113Sbill 32213Sbill dhwrite(dev) 3232395Swnj dev_t dev; 32413Sbill { 3252395Swnj register struct tty *tp; 32613Sbill 3272395Swnj tp = &dh11[minor(dev)]; 32813Sbill (*linesw[tp->t_line].l_write)(tp); 32913Sbill } 33013Sbill 33113Sbill /* 33213Sbill * DH11 receiver interrupt. 33313Sbill */ 3342395Swnj dhrint(dh) 3352395Swnj int dh; 33613Sbill { 33713Sbill register struct tty *tp; 3382395Swnj register c; 3392479Swnj register struct dhdevice *addr; 340117Sbill register struct tty *tp0; 3412974Swnj register struct uba_device *ui; 3422924Swnj int overrun = 0; 34313Sbill 3442395Swnj ui = dhinfo[dh]; 3452479Swnj if (ui == 0 || ui->ui_alive == 0) 3462479Swnj return; 3472479Swnj addr = (struct dhdevice *)ui->ui_addr; 3482468Swnj tp0 = &dh11[dh<<4]; 3492468Swnj /* 3502468Swnj * Loop fetching characters from the silo for this 3512468Swnj * dh until there are no more in the silo. 3522468Swnj */ 3532468Swnj while ((c = addr->dhrcr) < 0) { 3542468Swnj tp = tp0 + ((c>>8)&0xf); 3556615Ssam #ifndef PORTSELECTOR 3565406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 3576615Ssam #else 3586615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 3596615Ssam #endif 36013Sbill wakeup((caddr_t)tp); 36113Sbill continue; 36213Sbill } 3632468Swnj if (c & DH_PE) 36413Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 36513Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 36613Sbill continue; 3672924Swnj if ((c & DH_DO) && overrun == 0) { 3682924Swnj printf("dh%d: silo overflow\n", dh); 3692924Swnj overrun = 1; 3702924Swnj } 3712468Swnj if (c & DH_FE) 3722468Swnj /* 3732468Swnj * At framing error (break) generate 3742468Swnj * a null (in raw mode, for getty), or a 3752468Swnj * interrupt (in cooked/cbreak mode). 3762468Swnj */ 37713Sbill if (tp->t_flags&RAW) 3782468Swnj c = 0; 37913Sbill else 380184Sbill c = tun.t_intrc; 3812730Swnj #if NBK > 0 382139Sbill if (tp->t_line == NETLDISC) { 383117Sbill c &= 0177; 384168Sbill BKINPUT(c, tp); 385117Sbill } else 3862730Swnj #endif 3872468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 38813Sbill } 38913Sbill } 39013Sbill 39113Sbill /* 3922468Swnj * Ioctl for DH11. 39313Sbill */ 39413Sbill /*ARGSUSED*/ 3957629Ssam dhioctl(dev, cmd, data, flag) 3967629Ssam caddr_t data; 39713Sbill { 39813Sbill register struct tty *tp; 3992395Swnj register unit = minor(dev); 40013Sbill 4012395Swnj tp = &dh11[unit]; 4027629Ssam cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 4032468Swnj if (cmd == 0) 404113Sbill return; 4057629Ssam if (ttioctl(tp, cmd, data, flag)) { 4067629Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 4072395Swnj dhparam(unit); 408168Sbill } else switch(cmd) { 4097629Ssam 410168Sbill case TIOCSBRK: 4112479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 412168Sbill break; 4137629Ssam 414168Sbill case TIOCCBRK: 4152479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 416168Sbill break; 4177629Ssam 418168Sbill case TIOCSDTR: 4192479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 420168Sbill break; 4217629Ssam 422168Sbill case TIOCCDTR: 4232479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 424168Sbill break; 4257629Ssam 426168Sbill default: 42713Sbill u.u_error = ENOTTY; 428168Sbill } 42913Sbill } 43013Sbill 43113Sbill /* 43213Sbill * Set parameters from open or stty into the DH hardware 43313Sbill * registers. 43413Sbill */ 4352395Swnj dhparam(unit) 4362395Swnj register int unit; 43713Sbill { 43813Sbill register struct tty *tp; 4392479Swnj register struct dhdevice *addr; 4402395Swnj register int lpar; 441300Sbill int s; 44213Sbill 4432395Swnj tp = &dh11[unit]; 4442479Swnj addr = (struct dhdevice *)tp->t_addr; 4452468Swnj /* 4462468Swnj * Block interrupts so parameters will be set 4472468Swnj * before the line interrupts. 4482468Swnj */ 449300Sbill s = spl5(); 4502468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 45113Sbill if ((tp->t_ispeed)==0) { 4525406Swnj tp->t_state |= TS_HUPCLS; 4532479Swnj dmctl(unit, DML_OFF, DMSET); 45413Sbill return; 45513Sbill } 4562395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4572468Swnj if ((tp->t_ispeed) == B134) 4582395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4592312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4602395Swnj lpar |= BITS8; 46113Sbill else 4622395Swnj lpar |= BITS7|PENABLE; 46313Sbill if ((tp->t_flags&EVENP) == 0) 4642395Swnj lpar |= OPAR; 4652468Swnj if ((tp->t_ospeed) == B110) 4662395Swnj lpar |= TWOSB; 4672395Swnj addr->dhlpr = lpar; 468300Sbill splx(s); 46913Sbill } 47013Sbill 47113Sbill /* 47213Sbill * DH11 transmitter interrupt. 47313Sbill * Restart each line which used to be active but has 47413Sbill * terminated transmission since the last interrupt. 47513Sbill */ 4762395Swnj dhxint(dh) 4772395Swnj int dh; 47813Sbill { 47913Sbill register struct tty *tp; 4802479Swnj register struct dhdevice *addr; 48113Sbill short ttybit, bar, *sbar; 4822974Swnj register struct uba_device *ui; 4832468Swnj register int unit; 4842605Swnj u_short cntr; 48513Sbill 4862395Swnj ui = dhinfo[dh]; 4872479Swnj addr = (struct dhdevice *)ui->ui_addr; 4882456Swnj if (addr->un.dhcsr & DH_NXM) { 4892456Swnj addr->un.dhcsr |= DH_CNI; 4902924Swnj printf("dh%d: NXM\n", dh); 491105Sbill } 4922395Swnj sbar = &dhsar[dh]; 49313Sbill bar = *sbar & ~addr->dhbar; 4942395Swnj unit = dh * 16; ttybit = 1; 4952468Swnj addr->un.dhcsr &= (short)~DH_TI; 4962468Swnj for (; bar; unit++, ttybit <<= 1) { 4972468Swnj if (bar & ttybit) { 49813Sbill *sbar &= ~ttybit; 49913Sbill bar &= ~ttybit; 5002395Swnj tp = &dh11[unit]; 5015406Swnj tp->t_state &= ~TS_BUSY; 5025406Swnj if (tp->t_state&TS_FLUSH) 5035406Swnj tp->t_state &= ~TS_FLUSH; 504113Sbill else { 5052456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 5062468Swnj /* 5072468Swnj * Do arithmetic in a short to make up 5082468Swnj * for lost 16&17 bits. 5092468Swnj */ 5102605Swnj cntr = addr->dhcar - 5112468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 5123101Swnj ndflush(&tp->t_outq, (int)cntr); 513113Sbill } 514113Sbill if (tp->t_line) 51513Sbill (*linesw[tp->t_line].l_start)(tp); 516113Sbill else 51713Sbill dhstart(tp); 51813Sbill } 51913Sbill } 52013Sbill } 52113Sbill 52213Sbill /* 52313Sbill * Start (restart) transmission on the given DH11 line. 52413Sbill */ 52513Sbill dhstart(tp) 5262395Swnj register struct tty *tp; 52713Sbill { 5282479Swnj register struct dhdevice *addr; 5292468Swnj register int car, dh, unit, nch; 5302395Swnj int s; 53113Sbill 5322468Swnj unit = minor(tp->t_dev); 5332468Swnj dh = unit >> 4; 5342468Swnj unit &= 0xf; 5352479Swnj addr = (struct dhdevice *)tp->t_addr; 5362468Swnj 53713Sbill /* 5382468Swnj * Must hold interrupts in following code to prevent 5392468Swnj * state of the tp from changing. 54013Sbill */ 54113Sbill s = spl5(); 5422468Swnj /* 5432468Swnj * If it's currently active, or delaying, no need to do anything. 5442468Swnj */ 5455406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 54613Sbill goto out; 5472468Swnj /* 5482468Swnj * If there are sleepers, and output has drained below low 5492468Swnj * water mark, wake up the sleepers. 5502468Swnj */ 5515406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5525406Swnj if (tp->t_state&TS_ASLEEP) { 5535406Swnj tp->t_state &= ~TS_ASLEEP; 5545406Swnj wakeup((caddr_t)&tp->t_outq); 5555406Swnj } 5565406Swnj if (tp->t_wsel) { 5575406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5585406Swnj tp->t_wsel = 0; 5595406Swnj tp->t_state &= ~TS_WCOLL; 5605406Swnj } 56113Sbill } 5622468Swnj /* 5632468Swnj * Now restart transmission unless the output queue is 5642468Swnj * empty. 5652468Swnj */ 56613Sbill if (tp->t_outq.c_cc == 0) 56713Sbill goto out; 5683703Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 56913Sbill nch = ndqb(&tp->t_outq, 0); 5702395Swnj else { 57113Sbill nch = ndqb(&tp->t_outq, 0200); 5722468Swnj /* 5732468Swnj * If first thing on queue is a delay process it. 5742468Swnj */ 57513Sbill if (nch == 0) { 57613Sbill nch = getc(&tp->t_outq); 5772468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5785406Swnj tp->t_state |= TS_TIMEOUT; 57913Sbill goto out; 58013Sbill } 58113Sbill } 5822468Swnj /* 5832468Swnj * If characters to transmit, restart transmission. 5842468Swnj */ 58513Sbill if (nch) { 5862468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5872468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5883586Sroot /* 5893586Sroot * The following nonsense with short word 5903586Sroot * is to make sure the dhbar |= word below 5913586Sroot * is done with an interlocking bisw2 instruction. 5923586Sroot */ 5933586Sroot { short word = 1 << unit; 5943586Sroot dhsar[dh] |= word; 5952468Swnj addr->dhcar = car; 59613Sbill addr->dhbcr = -nch; 5973586Sroot addr->dhbar |= word; 5983586Sroot } 5995406Swnj tp->t_state |= TS_BUSY; 60013Sbill } 6012395Swnj out: 60213Sbill splx(s); 60313Sbill } 60413Sbill 60513Sbill /* 6062468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 60713Sbill */ 60813Sbill /*ARGSUSED*/ 60913Sbill dhstop(tp, flag) 6102468Swnj register struct tty *tp; 61113Sbill { 6122479Swnj register struct dhdevice *addr; 6132395Swnj register int unit, s; 61413Sbill 6152479Swnj addr = (struct dhdevice *)tp->t_addr; 6162468Swnj /* 6172468Swnj * Block input/output interrupts while messing with state. 6182468Swnj */ 6192468Swnj s = spl5(); 6205406Swnj if (tp->t_state & TS_BUSY) { 6212468Swnj /* 6222468Swnj * Device is transmitting; stop output 6232468Swnj * by selecting the line and setting the byte 6242468Swnj * count to -1. We will clean up later 6252468Swnj * by examining the address where the dh stopped. 6262468Swnj */ 6272395Swnj unit = minor(tp->t_dev); 6282456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6295406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6305406Swnj tp->t_state |= TS_FLUSH; 631113Sbill addr->dhbcr = -1; 632113Sbill } 63313Sbill splx(s); 63413Sbill } 63513Sbill 636168Sbill /* 637280Sbill * Reset state of driver if UBA reset was necessary. 638280Sbill * Reset the csrl and lpr registers on open lines, and 639280Sbill * restart transmitters. 640280Sbill */ 6412395Swnj dhreset(uban) 6422468Swnj int uban; 643280Sbill { 6442395Swnj register int dh, unit; 645280Sbill register struct tty *tp; 6462974Swnj register struct uba_device *ui; 6472421Skre int i; 648280Sbill 6492421Skre if (dh_ubinfo[uban] == 0) 6502421Skre return; 6512421Skre ubarelse(uban, &dh_ubinfo[uban]); 6522421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6532770Swnj 512+nclist*sizeof (struct cblock), 0); 6542421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6552395Swnj dh = 0; 6562643Swnj for (dh = 0; dh < NDH; dh++) { 6572421Skre ui = dhinfo[dh]; 6582421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6592421Skre continue; 6602924Swnj printf(" dh%d", dh); 6612479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6622479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6632421Skre unit = dh * 16; 6642421Skre for (i = 0; i < 16; i++) { 6652421Skre tp = &dh11[unit]; 6665406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6672421Skre dhparam(unit); 6682479Swnj dmctl(unit, DML_ON, DMSET); 6695406Swnj tp->t_state &= ~TS_BUSY; 6702421Skre dhstart(tp); 6712421Skre } 6722421Skre unit++; 673300Sbill } 674300Sbill } 675300Sbill dhtimer(); 676280Sbill } 6772395Swnj 6782468Swnj /* 6792468Swnj * At software clock interrupt time or after a UNIBUS reset 6802468Swnj * empty all the dh silos. 6812468Swnj */ 6822456Swnj dhtimer() 6832456Swnj { 6842456Swnj register int dh; 6852456Swnj 6862643Swnj for (dh = 0; dh < NDH; dh++) 6872456Swnj dhrint(dh); 6882456Swnj } 6892456Swnj 6902468Swnj /* 6912479Swnj * Turn on the line associated with dh dev. 6922468Swnj */ 6932468Swnj dmopen(dev) 6942468Swnj dev_t dev; 6952468Swnj { 6962468Swnj register struct tty *tp; 6972468Swnj register struct dmdevice *addr; 6982974Swnj register struct uba_device *ui; 6992468Swnj register int unit; 7002468Swnj register int dm; 7013792Swnj int s; 7022468Swnj 7032468Swnj unit = minor(dev); 7042479Swnj dm = unit >> 4; 7052468Swnj tp = &dh11[unit]; 7062566Swnj unit &= 0xf; 7072643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 7082566Swnj (dhsoftCAR[dm]&(1<<unit))) { 7095406Swnj tp->t_state |= TS_CARR_ON; 7102468Swnj return; 7112468Swnj } 7122468Swnj addr = (struct dmdevice *)ui->ui_addr; 7133792Swnj s = spl5(); 7142479Swnj addr->dmcsr &= ~DM_SE; 7152479Swnj while (addr->dmcsr & DM_BUSY) 7162468Swnj ; 7172566Swnj addr->dmcsr = unit; 7182479Swnj addr->dmlstat = DML_ON; 7192479Swnj if (addr->dmlstat&DML_CAR) 7205406Swnj tp->t_state |= TS_CARR_ON; 7213792Swnj addr->dmcsr = DM_IE|DM_SE; 7225406Swnj while ((tp->t_state&TS_CARR_ON)==0) 7232468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7243792Swnj splx(s); 7252468Swnj } 7262468Swnj 7272468Swnj /* 7282468Swnj * Dump control bits into the DM registers. 7292468Swnj */ 7302468Swnj dmctl(dev, bits, how) 7312468Swnj dev_t dev; 7322468Swnj int bits, how; 7332468Swnj { 7342974Swnj register struct uba_device *ui; 7352468Swnj register struct dmdevice *addr; 7362468Swnj register int unit, s; 7372468Swnj int dm; 7382468Swnj 7392468Swnj unit = minor(dev); 7402468Swnj dm = unit >> 4; 7412468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7422468Swnj return; 7432468Swnj addr = (struct dmdevice *)ui->ui_addr; 7442468Swnj s = spl5(); 7452479Swnj addr->dmcsr &= ~DM_SE; 7462479Swnj while (addr->dmcsr & DM_BUSY) 7472468Swnj ; 7482468Swnj addr->dmcsr = unit & 0xf; 7492468Swnj switch(how) { 7502468Swnj case DMSET: 7512468Swnj addr->dmlstat = bits; 7522468Swnj break; 7532468Swnj case DMBIS: 7542468Swnj addr->dmlstat |= bits; 7552468Swnj break; 7562468Swnj case DMBIC: 7572468Swnj addr->dmlstat &= ~bits; 7582468Swnj break; 7592468Swnj } 7603792Swnj addr->dmcsr = DM_IE|DM_SE; 7612468Swnj splx(s); 7622468Swnj } 7632468Swnj 7642468Swnj /* 7652468Swnj * DM11 interrupt; deal with carrier transitions. 7662468Swnj */ 7672468Swnj dmintr(dm) 7682468Swnj register int dm; 7692468Swnj { 7702974Swnj register struct uba_device *ui; 7712468Swnj register struct tty *tp; 7722468Swnj register struct dmdevice *addr; 7732468Swnj 7742468Swnj ui = dminfo[dm]; 7752479Swnj if (ui == 0) 7762479Swnj return; 7772468Swnj addr = (struct dmdevice *)ui->ui_addr; 7783997Sroot if (addr->dmcsr&DM_DONE) { 7793997Sroot if (addr->dmcsr&DM_CF) { 7803997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7813997Sroot wakeup((caddr_t)&tp->t_rawq); 7825406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7833997Sroot (tp->t_local&LMDMBUF)) { 7843997Sroot if (addr->dmlstat & DML_CAR) { 7855406Swnj tp->t_state &= ~TS_TTSTOP; 7863997Sroot ttstart(tp); 7875406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7885406Swnj tp->t_state |= TS_TTSTOP; 7893997Sroot dhstop(tp, 0); 7903997Sroot } 7913997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7925406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7933997Sroot (tp->t_local&LNOHANG)==0) { 7943997Sroot gsignal(tp->t_pgrp, SIGHUP); 7953997Sroot gsignal(tp->t_pgrp, SIGCONT); 7963997Sroot addr->dmlstat = 0; 7973997Sroot flushtty(tp, FREAD|FWRITE); 7983997Sroot } 7995406Swnj tp->t_state &= ~TS_CARR_ON; 8003997Sroot } else 8015406Swnj tp->t_state |= TS_CARR_ON; 8023997Sroot } 8033997Sroot addr->dmcsr = DM_IE|DM_SE; 8042468Swnj } 8052468Swnj } 8062625Swnj #endif 807