1*9605Ssam /* dh.c 4.55 82/12/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" 136185Ssam #include "../h/proc.h" 149549Ssam #include "../h/ioctl.h" 1513Sbill #include "../h/tty.h" 1613Sbill #include "../h/map.h" 1713Sbill #include "../h/pte.h" 182395Swnj #include "../h/buf.h" 192566Swnj #include "../h/vm.h" 208472Sroot 218472Sroot #include "../vaxuba/ubareg.h" 228472Sroot #include "../vaxuba/ubavar.h" 238472Sroot 24113Sbill #include "../h/bk.h" 251561Sbill #include "../h/clist.h" 262468Swnj #include "../h/file.h" 277725Sroot #include "../h/uio.h" 2813Sbill 292468Swnj /* 302479Swnj * Definition of the driver for the auto-configuration program. 312479Swnj * There is one definition for the dh and one for the dm. 322468Swnj */ 332605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 342974Swnj struct uba_device *dhinfo[NDH]; 352395Swnj u_short dhstd[] = { 0 }; 362395Swnj struct uba_driver dhdriver = 372605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 382395Swnj 392605Swnj int dmprobe(), dmattach(), dmintr(); 402974Swnj struct uba_device *dminfo[NDH]; 412479Swnj u_short dmstd[] = { 0 }; 422479Swnj struct uba_driver dmdriver = 432605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4413Sbill 452479Swnj struct dhdevice 462479Swnj { 472479Swnj union { 482479Swnj short dhcsr; /* control-status register */ 492479Swnj char dhcsrl; /* low byte for line select */ 502479Swnj } un; 512479Swnj short dhrcr; /* receive character register */ 522479Swnj short dhlpr; /* line parameter register */ 532479Swnj u_short dhcar; /* current address register */ 542479Swnj short dhbcr; /* byte count register */ 552479Swnj u_short dhbar; /* buffer active register */ 562479Swnj short dhbreak; /* break control register */ 572479Swnj short dhsilo; /* silo status register */ 582479Swnj }; 5913Sbill 606615Ssam #ifndef PORTSELECTOR 616615Ssam #define ISPEED B300 626615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 636615Ssam #else 646615Ssam #define ISPEED B4800 656615Ssam #define IFLAGS (EVENP|ODDP) 666615Ssam #endif 676615Ssam 682456Swnj /* Bits in dhcsr */ 692456Swnj #define DH_TI 0100000 /* transmit interrupt */ 702456Swnj #define DH_SI 0040000 /* storage interrupt */ 712456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 722456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 732456Swnj #define DH_MC 0004000 /* master clear */ 742456Swnj #define DH_NXM 0002000 /* non-existant memory */ 752456Swnj #define DH_MM 0001000 /* maintenance mode */ 762456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 772456Swnj #define DH_RI 0000200 /* receiver interrupt */ 782456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 7913Sbill 802479Swnj /* Bits in dhlpr */ 812479Swnj #define BITS6 01 822479Swnj #define BITS7 02 832479Swnj #define BITS8 03 842479Swnj #define TWOSB 04 852479Swnj #define PENABLE 020 862479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 872479Swnj #define OPAR 040 882479Swnj #define HDUPLX 040000 892479Swnj 902456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 912456Swnj 922456Swnj /* Bits in dhrcr */ 932479Swnj #define DH_PE 0010000 /* parity error */ 942479Swnj #define DH_FE 0020000 /* framing error */ 952479Swnj #define DH_DO 0040000 /* data overrun */ 962456Swnj 972479Swnj struct dmdevice 982479Swnj { 992479Swnj short dmcsr; /* control status register */ 1002479Swnj short dmlstat; /* line status register */ 1012479Swnj short dmpad1[2]; 1022479Swnj }; 1032479Swnj 1042479Swnj /* bits in dm csr */ 1052479Swnj #define DM_RF 0100000 /* ring flag */ 1062479Swnj #define DM_CF 0040000 /* carrier flag */ 1072479Swnj #define DM_CTS 0020000 /* clear to send */ 1082479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 1092479Swnj #define DM_CS 0004000 /* clear scan */ 1102479Swnj #define DM_CM 0002000 /* clear multiplexor */ 1112479Swnj #define DM_MM 0001000 /* maintenance mode */ 1122479Swnj #define DM_STP 0000400 /* step */ 1132479Swnj #define DM_DONE 0000200 /* scanner is done */ 1142479Swnj #define DM_IE 0000100 /* interrupt enable */ 1152479Swnj #define DM_SE 0000040 /* scan enable */ 1162479Swnj #define DM_BUSY 0000020 /* scan busy */ 1172479Swnj 1182479Swnj /* bits in dm lsr */ 1192479Swnj #define DML_RNG 0000200 /* ring */ 1202479Swnj #define DML_CAR 0000100 /* carrier detect */ 1212479Swnj #define DML_CTS 0000040 /* clear to send */ 1222479Swnj #define DML_SR 0000020 /* secondary receive */ 1232479Swnj #define DML_ST 0000010 /* secondary transmit */ 1242479Swnj #define DML_RTS 0000004 /* request to send */ 1252479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1262479Swnj #define DML_LE 0000001 /* line enable */ 1272479Swnj 1283792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1292479Swnj #define DML_OFF (DML_LE) 1302479Swnj 13113Sbill /* 1322479Swnj * Local variables for the driver 13313Sbill */ 1342643Swnj short dhsar[NDH]; /* software copy of last bar */ 1352643Swnj short dhsoftCAR[NDH]; 13613Sbill 1372643Swnj struct tty dh11[NDH*16]; 1382643Swnj int ndh11 = NDH*16; 1392479Swnj int dhact; /* mask of active dh's */ 1402479Swnj int dhstart(), ttrstrt(); 14113Sbill 1422479Swnj /* 1432479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1442479Swnj * The UBACVT macro converts a clist space address for unibus uban 1452479Swnj * into an i/o space address for the DMA routine. 1462479Swnj */ 1472479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1482479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1492479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 15013Sbill 1512456Swnj /* 1522456Swnj * Routine for configuration to force a dh to interrupt. 1532456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1542456Swnj */ 1552468Swnj /*ARGSUSED*/ 1562605Swnj dhprobe(reg) 1572395Swnj caddr_t reg; 1582395Swnj { 1592468Swnj register int br, cvec; /* these are ``value-result'' */ 1602479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1612395Swnj 1622605Swnj #ifdef lint 1632605Swnj br = 0; cvec = br; br = cvec; 1647384Sroot if (ndh11 == 0) ndh11 = 1; 1654932Swnj dhrint(0); dhxint(0); 1662605Swnj #endif 1672696Swnj #ifndef notdef 1682566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1696380Swnj DELAY(1000); 1707384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1712566Swnj dhaddr->un.dhcsr = 0; 1722566Swnj #else 1732456Swnj dhaddr->un.dhcsr = DH_TIE; 1742456Swnj DELAY(5); 1752456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1762421Skre dhaddr->dhbcr = -1; 1772456Swnj dhaddr->dhcar = 0; 1782421Skre dhaddr->dhbar = 1; 1792456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1802421Skre dhaddr->un.dhcsr = 0; 1812456Swnj if (cvec && cvec != 0x200) 1822456Swnj cvec -= 4; /* transmit -> receive */ 1832482Swnj #endif 1847408Skre return (sizeof (struct dhdevice)); 1852395Swnj } 1862395Swnj 1872456Swnj /* 1882605Swnj * Routine called to attach a dh. 1892456Swnj */ 1902605Swnj dhattach(ui) 1912974Swnj struct uba_device *ui; 1922395Swnj { 1932395Swnj 1942566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1952395Swnj } 1962395Swnj 19713Sbill /* 1982479Swnj * Configuration routine to cause a dm to interrupt. 1992479Swnj */ 2002605Swnj dmprobe(reg) 2012605Swnj caddr_t reg; 2022479Swnj { 2032479Swnj register int br, vec; /* value-result */ 2042605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 2052479Swnj 2062605Swnj #ifdef lint 2073101Swnj br = 0; vec = br; br = vec; 2086185Ssam dmintr(0); 2092605Swnj #endif 2102479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 2112479Swnj DELAY(20); 2122479Swnj dmaddr->dmcsr = 0; 2132605Swnj return (1); 2142479Swnj } 2152479Swnj 2162605Swnj /*ARGSUSED*/ 2172605Swnj dmattach(ui) 2182974Swnj struct uba_device *ui; 2192479Swnj { 2202479Swnj 2212479Swnj /* no local state to set up */ 2222479Swnj } 2232479Swnj 2242479Swnj /* 2252468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2262468Swnj * is the first dh on this uba. Turn on this dh if this is 2272468Swnj * the first use of it. Also do a dmopen to wait for carrier. 22813Sbill */ 22913Sbill /*ARGSUSED*/ 23013Sbill dhopen(dev, flag) 2312395Swnj dev_t dev; 23213Sbill { 23313Sbill register struct tty *tp; 2342395Swnj register int unit, dh; 2352479Swnj register struct dhdevice *addr; 2362974Swnj register struct uba_device *ui; 23713Sbill int s; 23813Sbill 2392395Swnj unit = minor(dev); 2402395Swnj dh = unit >> 4; 2418566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 2428566Sroot return (ENXIO); 2432395Swnj tp = &dh11[unit]; 2448566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2458566Sroot return (EBUSY); 2462479Swnj addr = (struct dhdevice *)ui->ui_addr; 24713Sbill tp->t_addr = (caddr_t)addr; 24813Sbill tp->t_oproc = dhstart; 2495406Swnj tp->t_state |= TS_WOPEN; 2502468Swnj /* 2512468Swnj * While setting up state for this uba and this dh, 2522468Swnj * block uba resets which can clear the state. 2532468Swnj */ 2542468Swnj s = spl5(); 2552421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 256717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2572395Swnj dh_ubinfo[ui->ui_ubanum] = 2582421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2592770Swnj 512+nclist*sizeof(struct cblock), 0); 2602456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 26113Sbill } 2622456Swnj if ((dhact&(1<<dh)) == 0) { 2632456Swnj addr->un.dhcsr |= DH_IE; 2642468Swnj dhact |= (1<<dh); 2652456Swnj addr->dhsilo = 16; 2662456Swnj } 26713Sbill splx(s); 2682468Swnj /* 2692468Swnj * If this is first open, initialze tty state to default. 2702468Swnj */ 2715406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 27213Sbill ttychars(tp); 2736615Ssam #ifndef PORTSELECTOR 274168Sbill if (tp->t_ispeed == 0) { 2756615Ssam #endif 2766615Ssam tp->t_ispeed = ISPEED; 2776615Ssam tp->t_ospeed = ISPEED; 2786615Ssam tp->t_flags = IFLAGS; 2796615Ssam #ifndef PORTSELECTOR 280168Sbill } 2816615Ssam #endif 2822395Swnj dhparam(unit); 28313Sbill } 2842468Swnj /* 2852468Swnj * Wait for carrier, then process line discipline specific open. 2862468Swnj */ 28713Sbill dmopen(dev); 2888566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 28913Sbill } 29013Sbill 29113Sbill /* 2922468Swnj * Close a DH11 line, turning off the DM11. 29313Sbill */ 29413Sbill /*ARGSUSED*/ 29513Sbill dhclose(dev, flag) 2962395Swnj dev_t dev; 2972395Swnj int flag; 29813Sbill { 29913Sbill register struct tty *tp; 3002395Swnj register unit; 30113Sbill 3022395Swnj unit = minor(dev); 3032395Swnj tp = &dh11[unit]; 30413Sbill (*linesw[tp->t_line].l_close)(tp); 3052479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 3065406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3072479Swnj dmctl(unit, DML_OFF, DMSET); 30813Sbill ttyclose(tp); 30913Sbill } 31013Sbill 3117725Sroot dhread(dev, uio) 3122395Swnj dev_t dev; 3137725Sroot struct uio *uio; 31413Sbill { 3158490Sroot register struct tty *tp = &dh11[minor(dev)]; 31613Sbill 3177725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 31813Sbill } 31913Sbill 3207831Sroot dhwrite(dev, uio) 3212395Swnj dev_t dev; 3227831Sroot struct uio *uio; 32313Sbill { 3248490Sroot register struct tty *tp = &dh11[minor(dev)]; 32513Sbill 3268490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 32713Sbill } 32813Sbill 32913Sbill /* 33013Sbill * DH11 receiver interrupt. 33113Sbill */ 3322395Swnj dhrint(dh) 3332395Swnj int dh; 33413Sbill { 33513Sbill register struct tty *tp; 3362395Swnj register c; 3372479Swnj register struct dhdevice *addr; 338117Sbill register struct tty *tp0; 3392974Swnj register struct uba_device *ui; 3402924Swnj int overrun = 0; 34113Sbill 3422395Swnj ui = dhinfo[dh]; 3432479Swnj if (ui == 0 || ui->ui_alive == 0) 3442479Swnj return; 3452479Swnj addr = (struct dhdevice *)ui->ui_addr; 3462468Swnj tp0 = &dh11[dh<<4]; 3472468Swnj /* 3482468Swnj * Loop fetching characters from the silo for this 3492468Swnj * dh until there are no more in the silo. 3502468Swnj */ 3512468Swnj while ((c = addr->dhrcr) < 0) { 3522468Swnj tp = tp0 + ((c>>8)&0xf); 3536615Ssam #ifndef PORTSELECTOR 3545406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 3556615Ssam #else 3566615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 3576615Ssam #endif 35813Sbill wakeup((caddr_t)tp); 35913Sbill continue; 36013Sbill } 3612468Swnj if (c & DH_PE) 36213Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 36313Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 36413Sbill continue; 3652924Swnj if ((c & DH_DO) && overrun == 0) { 3662924Swnj printf("dh%d: silo overflow\n", dh); 3672924Swnj overrun = 1; 3682924Swnj } 3692468Swnj if (c & DH_FE) 3702468Swnj /* 3712468Swnj * At framing error (break) generate 3722468Swnj * a null (in raw mode, for getty), or a 3732468Swnj * interrupt (in cooked/cbreak mode). 3742468Swnj */ 37513Sbill if (tp->t_flags&RAW) 3762468Swnj c = 0; 37713Sbill else 3789549Ssam c = tp->t_intrc; 3792730Swnj #if NBK > 0 380139Sbill if (tp->t_line == NETLDISC) { 381117Sbill c &= 0177; 382168Sbill BKINPUT(c, tp); 383117Sbill } else 3842730Swnj #endif 3852468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 38613Sbill } 38713Sbill } 38813Sbill 38913Sbill /* 3902468Swnj * Ioctl for DH11. 39113Sbill */ 39213Sbill /*ARGSUSED*/ 3937629Ssam dhioctl(dev, cmd, data, flag) 3947629Ssam caddr_t data; 39513Sbill { 39613Sbill register struct tty *tp; 3978566Sroot register int unit = minor(dev); 3988566Sroot int error; 39913Sbill 4002395Swnj tp = &dh11[unit]; 4018566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 4028566Sroot if (error >= 0) 4038566Sroot return (error); 4048566Sroot error = ttioctl(tp, cmd, data, flag); 4058566Sroot if (error >= 0) { 4067629Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 4072395Swnj dhparam(unit); 4088566Sroot return (error); 4098566Sroot } 4108566Sroot switch (cmd) { 4117629Ssam 412168Sbill case TIOCSBRK: 4132479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 414168Sbill break; 4157629Ssam 416168Sbill case TIOCCBRK: 4172479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 418168Sbill break; 4197629Ssam 420168Sbill case TIOCSDTR: 4212479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 422168Sbill break; 4237629Ssam 424168Sbill case TIOCCDTR: 4252479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 426168Sbill break; 4277629Ssam 428168Sbill default: 4298566Sroot return (ENOTTY); 430168Sbill } 4318566Sroot return (0); 43213Sbill } 43313Sbill 43413Sbill /* 43513Sbill * Set parameters from open or stty into the DH hardware 43613Sbill * registers. 43713Sbill */ 4382395Swnj dhparam(unit) 4392395Swnj register int unit; 44013Sbill { 44113Sbill register struct tty *tp; 4422479Swnj register struct dhdevice *addr; 4432395Swnj register int lpar; 444300Sbill int s; 44513Sbill 4462395Swnj tp = &dh11[unit]; 4472479Swnj addr = (struct dhdevice *)tp->t_addr; 4482468Swnj /* 4492468Swnj * Block interrupts so parameters will be set 4502468Swnj * before the line interrupts. 4512468Swnj */ 452300Sbill s = spl5(); 4532468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 45413Sbill if ((tp->t_ispeed)==0) { 4555406Swnj tp->t_state |= TS_HUPCLS; 4562479Swnj dmctl(unit, DML_OFF, DMSET); 45713Sbill return; 45813Sbill } 4592395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4602468Swnj if ((tp->t_ispeed) == B134) 4612395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4629549Ssam else if (tp->t_flags & (RAW|LITOUT)) 4632395Swnj lpar |= BITS8; 46413Sbill else 4652395Swnj lpar |= BITS7|PENABLE; 46613Sbill if ((tp->t_flags&EVENP) == 0) 4672395Swnj lpar |= OPAR; 4682468Swnj if ((tp->t_ospeed) == B110) 4692395Swnj lpar |= TWOSB; 4702395Swnj addr->dhlpr = lpar; 471300Sbill splx(s); 47213Sbill } 47313Sbill 47413Sbill /* 47513Sbill * DH11 transmitter interrupt. 47613Sbill * Restart each line which used to be active but has 47713Sbill * terminated transmission since the last interrupt. 47813Sbill */ 4792395Swnj dhxint(dh) 4802395Swnj int dh; 48113Sbill { 48213Sbill register struct tty *tp; 4832479Swnj register struct dhdevice *addr; 48413Sbill short ttybit, bar, *sbar; 4852974Swnj register struct uba_device *ui; 4862468Swnj register int unit; 4872605Swnj u_short cntr; 48813Sbill 4892395Swnj ui = dhinfo[dh]; 4902479Swnj addr = (struct dhdevice *)ui->ui_addr; 4912456Swnj if (addr->un.dhcsr & DH_NXM) { 4922456Swnj addr->un.dhcsr |= DH_CNI; 4932924Swnj printf("dh%d: NXM\n", dh); 494105Sbill } 4952395Swnj sbar = &dhsar[dh]; 49613Sbill bar = *sbar & ~addr->dhbar; 4972395Swnj unit = dh * 16; ttybit = 1; 4982468Swnj addr->un.dhcsr &= (short)~DH_TI; 4992468Swnj for (; bar; unit++, ttybit <<= 1) { 5002468Swnj if (bar & ttybit) { 50113Sbill *sbar &= ~ttybit; 50213Sbill bar &= ~ttybit; 5032395Swnj tp = &dh11[unit]; 5045406Swnj tp->t_state &= ~TS_BUSY; 5055406Swnj if (tp->t_state&TS_FLUSH) 5065406Swnj tp->t_state &= ~TS_FLUSH; 507113Sbill else { 5082456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 5092468Swnj /* 5102468Swnj * Do arithmetic in a short to make up 5112468Swnj * for lost 16&17 bits. 5122468Swnj */ 5132605Swnj cntr = addr->dhcar - 5142468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 5153101Swnj ndflush(&tp->t_outq, (int)cntr); 516113Sbill } 517113Sbill if (tp->t_line) 51813Sbill (*linesw[tp->t_line].l_start)(tp); 519113Sbill else 52013Sbill dhstart(tp); 52113Sbill } 52213Sbill } 52313Sbill } 52413Sbill 52513Sbill /* 52613Sbill * Start (restart) transmission on the given DH11 line. 52713Sbill */ 52813Sbill dhstart(tp) 5292395Swnj register struct tty *tp; 53013Sbill { 5312479Swnj register struct dhdevice *addr; 5322468Swnj register int car, dh, unit, nch; 5332395Swnj int s; 53413Sbill 5352468Swnj unit = minor(tp->t_dev); 5362468Swnj dh = unit >> 4; 5372468Swnj unit &= 0xf; 5382479Swnj addr = (struct dhdevice *)tp->t_addr; 5392468Swnj 54013Sbill /* 5412468Swnj * Must hold interrupts in following code to prevent 5422468Swnj * state of the tp from changing. 54313Sbill */ 54413Sbill s = spl5(); 5452468Swnj /* 5462468Swnj * If it's currently active, or delaying, no need to do anything. 5472468Swnj */ 5485406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 54913Sbill goto out; 5502468Swnj /* 5512468Swnj * If there are sleepers, and output has drained below low 5522468Swnj * water mark, wake up the sleepers. 5532468Swnj */ 5545406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5555406Swnj if (tp->t_state&TS_ASLEEP) { 5565406Swnj tp->t_state &= ~TS_ASLEEP; 5575406Swnj wakeup((caddr_t)&tp->t_outq); 5585406Swnj } 5595406Swnj if (tp->t_wsel) { 5605406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5615406Swnj tp->t_wsel = 0; 5625406Swnj tp->t_state &= ~TS_WCOLL; 5635406Swnj } 56413Sbill } 5652468Swnj /* 5662468Swnj * Now restart transmission unless the output queue is 5672468Swnj * empty. 5682468Swnj */ 56913Sbill if (tp->t_outq.c_cc == 0) 57013Sbill goto out; 5719549Ssam if (tp->t_flags & (RAW|LITOUT)) 57213Sbill nch = ndqb(&tp->t_outq, 0); 5732395Swnj else { 57413Sbill nch = ndqb(&tp->t_outq, 0200); 5752468Swnj /* 5762468Swnj * If first thing on queue is a delay process it. 5772468Swnj */ 57813Sbill if (nch == 0) { 57913Sbill nch = getc(&tp->t_outq); 5802468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5815406Swnj tp->t_state |= TS_TIMEOUT; 58213Sbill goto out; 58313Sbill } 58413Sbill } 5852468Swnj /* 5862468Swnj * If characters to transmit, restart transmission. 5872468Swnj */ 58813Sbill if (nch) { 5892468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5902468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5913586Sroot /* 5923586Sroot * The following nonsense with short word 5933586Sroot * is to make sure the dhbar |= word below 5943586Sroot * is done with an interlocking bisw2 instruction. 5953586Sroot */ 5963586Sroot { short word = 1 << unit; 5973586Sroot dhsar[dh] |= word; 5982468Swnj addr->dhcar = car; 59913Sbill addr->dhbcr = -nch; 6003586Sroot addr->dhbar |= word; 6013586Sroot } 6025406Swnj tp->t_state |= TS_BUSY; 60313Sbill } 6042395Swnj out: 60513Sbill splx(s); 60613Sbill } 60713Sbill 60813Sbill /* 6092468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 61013Sbill */ 61113Sbill /*ARGSUSED*/ 61213Sbill dhstop(tp, flag) 6132468Swnj register struct tty *tp; 61413Sbill { 6152479Swnj register struct dhdevice *addr; 6162395Swnj register int unit, s; 61713Sbill 6182479Swnj addr = (struct dhdevice *)tp->t_addr; 6192468Swnj /* 6202468Swnj * Block input/output interrupts while messing with state. 6212468Swnj */ 6222468Swnj s = spl5(); 6235406Swnj if (tp->t_state & TS_BUSY) { 6242468Swnj /* 6252468Swnj * Device is transmitting; stop output 6262468Swnj * by selecting the line and setting the byte 6272468Swnj * count to -1. We will clean up later 6282468Swnj * by examining the address where the dh stopped. 6292468Swnj */ 6302395Swnj unit = minor(tp->t_dev); 6312456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6325406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6335406Swnj tp->t_state |= TS_FLUSH; 634113Sbill addr->dhbcr = -1; 635113Sbill } 63613Sbill splx(s); 63713Sbill } 63813Sbill 639168Sbill /* 640280Sbill * Reset state of driver if UBA reset was necessary. 641280Sbill * Reset the csrl and lpr registers on open lines, and 642280Sbill * restart transmitters. 643280Sbill */ 6442395Swnj dhreset(uban) 6452468Swnj int uban; 646280Sbill { 6472395Swnj register int dh, unit; 648280Sbill register struct tty *tp; 6492974Swnj register struct uba_device *ui; 6502421Skre int i; 651280Sbill 6522421Skre if (dh_ubinfo[uban] == 0) 6532421Skre return; 6542421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6552770Swnj 512+nclist*sizeof (struct cblock), 0); 6562421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6572395Swnj dh = 0; 6582643Swnj for (dh = 0; dh < NDH; dh++) { 6592421Skre ui = dhinfo[dh]; 6602421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6612421Skre continue; 6622924Swnj printf(" dh%d", dh); 6632479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6642479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6652421Skre unit = dh * 16; 6662421Skre for (i = 0; i < 16; i++) { 6672421Skre tp = &dh11[unit]; 6685406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6692421Skre dhparam(unit); 6702479Swnj dmctl(unit, DML_ON, DMSET); 6715406Swnj tp->t_state &= ~TS_BUSY; 6722421Skre dhstart(tp); 6732421Skre } 6742421Skre unit++; 675300Sbill } 676300Sbill } 677300Sbill dhtimer(); 678280Sbill } 6792395Swnj 6802468Swnj /* 6812468Swnj * At software clock interrupt time or after a UNIBUS reset 6822468Swnj * empty all the dh silos. 6832468Swnj */ 6842456Swnj dhtimer() 6852456Swnj { 6862456Swnj register int dh; 6878159Sroot register int s = spl5(); 6882456Swnj 6892643Swnj for (dh = 0; dh < NDH; dh++) 6902456Swnj dhrint(dh); 6918159Sroot splx(s); 6922456Swnj } 6932456Swnj 6942468Swnj /* 6952479Swnj * Turn on the line associated with dh dev. 6962468Swnj */ 6972468Swnj dmopen(dev) 6982468Swnj dev_t dev; 6992468Swnj { 7002468Swnj register struct tty *tp; 7012468Swnj register struct dmdevice *addr; 7022974Swnj register struct uba_device *ui; 7032468Swnj register int unit; 7042468Swnj register int dm; 7053792Swnj int s; 7062468Swnj 7072468Swnj unit = minor(dev); 7082479Swnj dm = unit >> 4; 7092468Swnj tp = &dh11[unit]; 7102566Swnj unit &= 0xf; 7112643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 7122566Swnj (dhsoftCAR[dm]&(1<<unit))) { 7135406Swnj tp->t_state |= TS_CARR_ON; 7142468Swnj return; 7152468Swnj } 7162468Swnj addr = (struct dmdevice *)ui->ui_addr; 7173792Swnj s = spl5(); 7182479Swnj addr->dmcsr &= ~DM_SE; 7192479Swnj while (addr->dmcsr & DM_BUSY) 7202468Swnj ; 7212566Swnj addr->dmcsr = unit; 7222479Swnj addr->dmlstat = DML_ON; 7232479Swnj if (addr->dmlstat&DML_CAR) 7245406Swnj tp->t_state |= TS_CARR_ON; 7253792Swnj addr->dmcsr = DM_IE|DM_SE; 7265406Swnj while ((tp->t_state&TS_CARR_ON)==0) 7272468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7283792Swnj splx(s); 7292468Swnj } 7302468Swnj 7312468Swnj /* 7322468Swnj * Dump control bits into the DM registers. 7332468Swnj */ 7342468Swnj dmctl(dev, bits, how) 7352468Swnj dev_t dev; 7362468Swnj int bits, how; 7372468Swnj { 7382974Swnj register struct uba_device *ui; 7392468Swnj register struct dmdevice *addr; 7402468Swnj register int unit, s; 7412468Swnj int dm; 7422468Swnj 7432468Swnj unit = minor(dev); 7442468Swnj dm = unit >> 4; 7452468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7462468Swnj return; 7472468Swnj addr = (struct dmdevice *)ui->ui_addr; 7482468Swnj s = spl5(); 7492479Swnj addr->dmcsr &= ~DM_SE; 7502479Swnj while (addr->dmcsr & DM_BUSY) 7512468Swnj ; 7522468Swnj addr->dmcsr = unit & 0xf; 7532468Swnj switch(how) { 7542468Swnj case DMSET: 7552468Swnj addr->dmlstat = bits; 7562468Swnj break; 7572468Swnj case DMBIS: 7582468Swnj addr->dmlstat |= bits; 7592468Swnj break; 7602468Swnj case DMBIC: 7612468Swnj addr->dmlstat &= ~bits; 7622468Swnj break; 7632468Swnj } 7643792Swnj addr->dmcsr = DM_IE|DM_SE; 7652468Swnj splx(s); 7662468Swnj } 7672468Swnj 7682468Swnj /* 7692468Swnj * DM11 interrupt; deal with carrier transitions. 7702468Swnj */ 7712468Swnj dmintr(dm) 7722468Swnj register int dm; 7732468Swnj { 7742974Swnj register struct uba_device *ui; 7752468Swnj register struct tty *tp; 7762468Swnj register struct dmdevice *addr; 7772468Swnj 7782468Swnj ui = dminfo[dm]; 7792479Swnj if (ui == 0) 7802479Swnj return; 7812468Swnj addr = (struct dmdevice *)ui->ui_addr; 7823997Sroot if (addr->dmcsr&DM_DONE) { 7833997Sroot if (addr->dmcsr&DM_CF) { 7843997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7853997Sroot wakeup((caddr_t)&tp->t_rawq); 7869549Ssam if ((tp->t_state&TS_WOPEN) == 0 && 787*9605Ssam (tp->t_flags & MDMBUF)) { 7883997Sroot if (addr->dmlstat & DML_CAR) { 7895406Swnj tp->t_state &= ~TS_TTSTOP; 7903997Sroot ttstart(tp); 7915406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7925406Swnj tp->t_state |= TS_TTSTOP; 7933997Sroot dhstop(tp, 0); 7943997Sroot } 7953997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7965406Swnj if ((tp->t_state&TS_WOPEN)==0 && 797*9605Ssam (tp->t_flags & NOHANG) == 0) { 7983997Sroot gsignal(tp->t_pgrp, SIGHUP); 7993997Sroot gsignal(tp->t_pgrp, SIGCONT); 8003997Sroot addr->dmlstat = 0; 8013997Sroot flushtty(tp, FREAD|FWRITE); 8023997Sroot } 8035406Swnj tp->t_state &= ~TS_CARR_ON; 8043997Sroot } else 8055406Swnj tp->t_state |= TS_CARR_ON; 8063997Sroot } 8073997Sroot addr->dmcsr = DM_IE|DM_SE; 8082468Swnj } 8092468Swnj } 8102625Swnj #endif 811