1*8566Sroot /* dh.c 4.53 82/10/17 */ 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" 198472Sroot 208472Sroot #include "../vaxuba/ubareg.h" 218472Sroot #include "../vaxuba/ubavar.h" 228472Sroot 23113Sbill #include "../h/bk.h" 241561Sbill #include "../h/clist.h" 252468Swnj #include "../h/file.h" 267725Sroot #include "../h/uio.h" 2713Sbill 282468Swnj /* 292479Swnj * Definition of the driver for the auto-configuration program. 302479Swnj * There is one definition for the dh and one for the dm. 312468Swnj */ 322605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 332974Swnj struct uba_device *dhinfo[NDH]; 342395Swnj u_short dhstd[] = { 0 }; 352395Swnj struct uba_driver dhdriver = 362605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 372395Swnj 382605Swnj int dmprobe(), dmattach(), dmintr(); 392974Swnj struct uba_device *dminfo[NDH]; 402479Swnj u_short dmstd[] = { 0 }; 412479Swnj struct uba_driver dmdriver = 422605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4313Sbill 442479Swnj struct dhdevice 452479Swnj { 462479Swnj union { 472479Swnj short dhcsr; /* control-status register */ 482479Swnj char dhcsrl; /* low byte for line select */ 492479Swnj } un; 502479Swnj short dhrcr; /* receive character register */ 512479Swnj short dhlpr; /* line parameter register */ 522479Swnj u_short dhcar; /* current address register */ 532479Swnj short dhbcr; /* byte count register */ 542479Swnj u_short dhbar; /* buffer active register */ 552479Swnj short dhbreak; /* break control register */ 562479Swnj short dhsilo; /* silo status register */ 572479Swnj }; 5813Sbill 596615Ssam #ifndef PORTSELECTOR 606615Ssam #define ISPEED B300 616615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 626615Ssam #else 636615Ssam #define ISPEED B4800 646615Ssam #define IFLAGS (EVENP|ODDP) 656615Ssam #endif 666615Ssam 672456Swnj /* Bits in dhcsr */ 682456Swnj #define DH_TI 0100000 /* transmit interrupt */ 692456Swnj #define DH_SI 0040000 /* storage interrupt */ 702456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 712456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 722456Swnj #define DH_MC 0004000 /* master clear */ 732456Swnj #define DH_NXM 0002000 /* non-existant memory */ 742456Swnj #define DH_MM 0001000 /* maintenance mode */ 752456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 762456Swnj #define DH_RI 0000200 /* receiver interrupt */ 772456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 7813Sbill 792479Swnj /* Bits in dhlpr */ 802479Swnj #define BITS6 01 812479Swnj #define BITS7 02 822479Swnj #define BITS8 03 832479Swnj #define TWOSB 04 842479Swnj #define PENABLE 020 852479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 862479Swnj #define OPAR 040 872479Swnj #define HDUPLX 040000 882479Swnj 892456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 902456Swnj 912456Swnj /* Bits in dhrcr */ 922479Swnj #define DH_PE 0010000 /* parity error */ 932479Swnj #define DH_FE 0020000 /* framing error */ 942479Swnj #define DH_DO 0040000 /* data overrun */ 952456Swnj 962479Swnj struct dmdevice 972479Swnj { 982479Swnj short dmcsr; /* control status register */ 992479Swnj short dmlstat; /* line status register */ 1002479Swnj short dmpad1[2]; 1012479Swnj }; 1022479Swnj 1032479Swnj /* bits in dm csr */ 1042479Swnj #define DM_RF 0100000 /* ring flag */ 1052479Swnj #define DM_CF 0040000 /* carrier flag */ 1062479Swnj #define DM_CTS 0020000 /* clear to send */ 1072479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 1082479Swnj #define DM_CS 0004000 /* clear scan */ 1092479Swnj #define DM_CM 0002000 /* clear multiplexor */ 1102479Swnj #define DM_MM 0001000 /* maintenance mode */ 1112479Swnj #define DM_STP 0000400 /* step */ 1122479Swnj #define DM_DONE 0000200 /* scanner is done */ 1132479Swnj #define DM_IE 0000100 /* interrupt enable */ 1142479Swnj #define DM_SE 0000040 /* scan enable */ 1152479Swnj #define DM_BUSY 0000020 /* scan busy */ 1162479Swnj 1172479Swnj /* bits in dm lsr */ 1182479Swnj #define DML_RNG 0000200 /* ring */ 1192479Swnj #define DML_CAR 0000100 /* carrier detect */ 1202479Swnj #define DML_CTS 0000040 /* clear to send */ 1212479Swnj #define DML_SR 0000020 /* secondary receive */ 1222479Swnj #define DML_ST 0000010 /* secondary transmit */ 1232479Swnj #define DML_RTS 0000004 /* request to send */ 1242479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1252479Swnj #define DML_LE 0000001 /* line enable */ 1262479Swnj 1273792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1282479Swnj #define DML_OFF (DML_LE) 1292479Swnj 13013Sbill /* 1312479Swnj * Local variables for the driver 13213Sbill */ 1332643Swnj short dhsar[NDH]; /* software copy of last bar */ 1342643Swnj short dhsoftCAR[NDH]; 13513Sbill 1362643Swnj struct tty dh11[NDH*16]; 1372643Swnj int ndh11 = NDH*16; 1382479Swnj int dhact; /* mask of active dh's */ 1392479Swnj int dhstart(), ttrstrt(); 14013Sbill 1412479Swnj /* 1422479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1432479Swnj * The UBACVT macro converts a clist space address for unibus uban 1442479Swnj * into an i/o space address for the DMA routine. 1452479Swnj */ 1462479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1472479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1482479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 14913Sbill 1502456Swnj /* 1512456Swnj * Routine for configuration to force a dh to interrupt. 1522456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1532456Swnj */ 1542468Swnj /*ARGSUSED*/ 1552605Swnj dhprobe(reg) 1562395Swnj caddr_t reg; 1572395Swnj { 1582468Swnj register int br, cvec; /* these are ``value-result'' */ 1592479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1602395Swnj 1612605Swnj #ifdef lint 1622605Swnj br = 0; cvec = br; br = cvec; 1637384Sroot if (ndh11 == 0) ndh11 = 1; 1644932Swnj dhrint(0); dhxint(0); 1652605Swnj #endif 1662696Swnj #ifndef notdef 1672566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1686380Swnj DELAY(1000); 1697384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1702566Swnj dhaddr->un.dhcsr = 0; 1712566Swnj #else 1722456Swnj dhaddr->un.dhcsr = DH_TIE; 1732456Swnj DELAY(5); 1742456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1752421Skre dhaddr->dhbcr = -1; 1762456Swnj dhaddr->dhcar = 0; 1772421Skre dhaddr->dhbar = 1; 1782456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1792421Skre dhaddr->un.dhcsr = 0; 1802456Swnj if (cvec && cvec != 0x200) 1812456Swnj cvec -= 4; /* transmit -> receive */ 1822482Swnj #endif 1837408Skre return (sizeof (struct dhdevice)); 1842395Swnj } 1852395Swnj 1862456Swnj /* 1872605Swnj * Routine called to attach a dh. 1882456Swnj */ 1892605Swnj dhattach(ui) 1902974Swnj struct uba_device *ui; 1912395Swnj { 1922395Swnj 1932566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1942395Swnj } 1952395Swnj 19613Sbill /* 1972479Swnj * Configuration routine to cause a dm to interrupt. 1982479Swnj */ 1992605Swnj dmprobe(reg) 2002605Swnj caddr_t reg; 2012479Swnj { 2022479Swnj register int br, vec; /* value-result */ 2032605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 2042479Swnj 2052605Swnj #ifdef lint 2063101Swnj br = 0; vec = br; br = vec; 2076185Ssam dmintr(0); 2082605Swnj #endif 2092479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 2102479Swnj DELAY(20); 2112479Swnj dmaddr->dmcsr = 0; 2122605Swnj return (1); 2132479Swnj } 2142479Swnj 2152605Swnj /*ARGSUSED*/ 2162605Swnj dmattach(ui) 2172974Swnj struct uba_device *ui; 2182479Swnj { 2192479Swnj 2202479Swnj /* no local state to set up */ 2212479Swnj } 2222479Swnj 2232479Swnj /* 2242468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2252468Swnj * is the first dh on this uba. Turn on this dh if this is 2262468Swnj * the first use of it. Also do a dmopen to wait for carrier. 22713Sbill */ 22813Sbill /*ARGSUSED*/ 22913Sbill dhopen(dev, flag) 2302395Swnj dev_t dev; 23113Sbill { 23213Sbill register struct tty *tp; 2332395Swnj register int unit, dh; 2342479Swnj register struct dhdevice *addr; 2352974Swnj register struct uba_device *ui; 23613Sbill int s; 23713Sbill 2382395Swnj unit = minor(dev); 2392395Swnj dh = unit >> 4; 240*8566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 241*8566Sroot return (ENXIO); 2422395Swnj tp = &dh11[unit]; 243*8566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 244*8566Sroot return (EBUSY); 2452479Swnj addr = (struct dhdevice *)ui->ui_addr; 24613Sbill tp->t_addr = (caddr_t)addr; 24713Sbill tp->t_oproc = dhstart; 2485406Swnj tp->t_state |= TS_WOPEN; 2492468Swnj /* 2502468Swnj * While setting up state for this uba and this dh, 2512468Swnj * block uba resets which can clear the state. 2522468Swnj */ 2532468Swnj s = spl5(); 2542421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 255717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2562395Swnj dh_ubinfo[ui->ui_ubanum] = 2572421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2582770Swnj 512+nclist*sizeof(struct cblock), 0); 2592456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 26013Sbill } 2612456Swnj if ((dhact&(1<<dh)) == 0) { 2622456Swnj addr->un.dhcsr |= DH_IE; 2632468Swnj dhact |= (1<<dh); 2642456Swnj addr->dhsilo = 16; 2652456Swnj } 26613Sbill splx(s); 2672468Swnj /* 2682468Swnj * If this is first open, initialze tty state to default. 2692468Swnj */ 2705406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 27113Sbill ttychars(tp); 2726615Ssam #ifndef PORTSELECTOR 273168Sbill if (tp->t_ispeed == 0) { 2746615Ssam #endif 2756615Ssam tp->t_ispeed = ISPEED; 2766615Ssam tp->t_ospeed = ISPEED; 2776615Ssam tp->t_flags = IFLAGS; 2786615Ssam #ifndef PORTSELECTOR 279168Sbill } 2806615Ssam #endif 2812395Swnj dhparam(unit); 28213Sbill } 2832468Swnj /* 2842468Swnj * Wait for carrier, then process line discipline specific open. 2852468Swnj */ 28613Sbill dmopen(dev); 287*8566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 28813Sbill } 28913Sbill 29013Sbill /* 2912468Swnj * Close a DH11 line, turning off the DM11. 29213Sbill */ 29313Sbill /*ARGSUSED*/ 29413Sbill dhclose(dev, flag) 2952395Swnj dev_t dev; 2962395Swnj int flag; 29713Sbill { 29813Sbill register struct tty *tp; 2992395Swnj register unit; 30013Sbill 3012395Swnj unit = minor(dev); 3022395Swnj tp = &dh11[unit]; 30313Sbill (*linesw[tp->t_line].l_close)(tp); 3042479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 3055406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3062479Swnj dmctl(unit, DML_OFF, DMSET); 30713Sbill ttyclose(tp); 30813Sbill } 30913Sbill 3107725Sroot dhread(dev, uio) 3112395Swnj dev_t dev; 3127725Sroot struct uio *uio; 31313Sbill { 3148490Sroot register struct tty *tp = &dh11[minor(dev)]; 31513Sbill 3167725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 31713Sbill } 31813Sbill 3197831Sroot dhwrite(dev, uio) 3202395Swnj dev_t dev; 3217831Sroot struct uio *uio; 32213Sbill { 3238490Sroot register struct tty *tp = &dh11[minor(dev)]; 32413Sbill 3258490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 32613Sbill } 32713Sbill 32813Sbill /* 32913Sbill * DH11 receiver interrupt. 33013Sbill */ 3312395Swnj dhrint(dh) 3322395Swnj int dh; 33313Sbill { 33413Sbill register struct tty *tp; 3352395Swnj register c; 3362479Swnj register struct dhdevice *addr; 337117Sbill register struct tty *tp0; 3382974Swnj register struct uba_device *ui; 3392924Swnj int overrun = 0; 34013Sbill 3412395Swnj ui = dhinfo[dh]; 3422479Swnj if (ui == 0 || ui->ui_alive == 0) 3432479Swnj return; 3442479Swnj addr = (struct dhdevice *)ui->ui_addr; 3452468Swnj tp0 = &dh11[dh<<4]; 3462468Swnj /* 3472468Swnj * Loop fetching characters from the silo for this 3482468Swnj * dh until there are no more in the silo. 3492468Swnj */ 3502468Swnj while ((c = addr->dhrcr) < 0) { 3512468Swnj tp = tp0 + ((c>>8)&0xf); 3526615Ssam #ifndef PORTSELECTOR 3535406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 3546615Ssam #else 3556615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 3566615Ssam #endif 35713Sbill wakeup((caddr_t)tp); 35813Sbill continue; 35913Sbill } 3602468Swnj if (c & DH_PE) 36113Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 36213Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 36313Sbill continue; 3642924Swnj if ((c & DH_DO) && overrun == 0) { 3652924Swnj printf("dh%d: silo overflow\n", dh); 3662924Swnj overrun = 1; 3672924Swnj } 3682468Swnj if (c & DH_FE) 3692468Swnj /* 3702468Swnj * At framing error (break) generate 3712468Swnj * a null (in raw mode, for getty), or a 3722468Swnj * interrupt (in cooked/cbreak mode). 3732468Swnj */ 37413Sbill if (tp->t_flags&RAW) 3752468Swnj c = 0; 37613Sbill else 377184Sbill c = tun.t_intrc; 3782730Swnj #if NBK > 0 379139Sbill if (tp->t_line == NETLDISC) { 380117Sbill c &= 0177; 381168Sbill BKINPUT(c, tp); 382117Sbill } else 3832730Swnj #endif 3842468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 38513Sbill } 38613Sbill } 38713Sbill 38813Sbill /* 3892468Swnj * Ioctl for DH11. 39013Sbill */ 39113Sbill /*ARGSUSED*/ 3927629Ssam dhioctl(dev, cmd, data, flag) 3937629Ssam caddr_t data; 39413Sbill { 39513Sbill register struct tty *tp; 396*8566Sroot register int unit = minor(dev); 397*8566Sroot int error; 39813Sbill 3992395Swnj tp = &dh11[unit]; 400*8566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 401*8566Sroot if (error >= 0) 402*8566Sroot return (error); 403*8566Sroot error = ttioctl(tp, cmd, data, flag); 404*8566Sroot if (error >= 0) { 4057629Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 4062395Swnj dhparam(unit); 407*8566Sroot return (error); 408*8566Sroot } 409*8566Sroot switch (cmd) { 4107629Ssam 411168Sbill case TIOCSBRK: 4122479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 413168Sbill break; 4147629Ssam 415168Sbill case TIOCCBRK: 4162479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 417168Sbill break; 4187629Ssam 419168Sbill case TIOCSDTR: 4202479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 421168Sbill break; 4227629Ssam 423168Sbill case TIOCCDTR: 4242479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 425168Sbill break; 4267629Ssam 427168Sbill default: 428*8566Sroot return (ENOTTY); 429168Sbill } 430*8566Sroot return (0); 43113Sbill } 43213Sbill 43313Sbill /* 43413Sbill * Set parameters from open or stty into the DH hardware 43513Sbill * registers. 43613Sbill */ 4372395Swnj dhparam(unit) 4382395Swnj register int unit; 43913Sbill { 44013Sbill register struct tty *tp; 4412479Swnj register struct dhdevice *addr; 4422395Swnj register int lpar; 443300Sbill int s; 44413Sbill 4452395Swnj tp = &dh11[unit]; 4462479Swnj addr = (struct dhdevice *)tp->t_addr; 4472468Swnj /* 4482468Swnj * Block interrupts so parameters will be set 4492468Swnj * before the line interrupts. 4502468Swnj */ 451300Sbill s = spl5(); 4522468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 45313Sbill if ((tp->t_ispeed)==0) { 4545406Swnj tp->t_state |= TS_HUPCLS; 4552479Swnj dmctl(unit, DML_OFF, DMSET); 45613Sbill return; 45713Sbill } 4582395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4592468Swnj if ((tp->t_ispeed) == B134) 4602395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4612312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4622395Swnj lpar |= BITS8; 46313Sbill else 4642395Swnj lpar |= BITS7|PENABLE; 46513Sbill if ((tp->t_flags&EVENP) == 0) 4662395Swnj lpar |= OPAR; 4672468Swnj if ((tp->t_ospeed) == B110) 4682395Swnj lpar |= TWOSB; 4692395Swnj addr->dhlpr = lpar; 470300Sbill splx(s); 47113Sbill } 47213Sbill 47313Sbill /* 47413Sbill * DH11 transmitter interrupt. 47513Sbill * Restart each line which used to be active but has 47613Sbill * terminated transmission since the last interrupt. 47713Sbill */ 4782395Swnj dhxint(dh) 4792395Swnj int dh; 48013Sbill { 48113Sbill register struct tty *tp; 4822479Swnj register struct dhdevice *addr; 48313Sbill short ttybit, bar, *sbar; 4842974Swnj register struct uba_device *ui; 4852468Swnj register int unit; 4862605Swnj u_short cntr; 48713Sbill 4882395Swnj ui = dhinfo[dh]; 4892479Swnj addr = (struct dhdevice *)ui->ui_addr; 4902456Swnj if (addr->un.dhcsr & DH_NXM) { 4912456Swnj addr->un.dhcsr |= DH_CNI; 4922924Swnj printf("dh%d: NXM\n", dh); 493105Sbill } 4942395Swnj sbar = &dhsar[dh]; 49513Sbill bar = *sbar & ~addr->dhbar; 4962395Swnj unit = dh * 16; ttybit = 1; 4972468Swnj addr->un.dhcsr &= (short)~DH_TI; 4982468Swnj for (; bar; unit++, ttybit <<= 1) { 4992468Swnj if (bar & ttybit) { 50013Sbill *sbar &= ~ttybit; 50113Sbill bar &= ~ttybit; 5022395Swnj tp = &dh11[unit]; 5035406Swnj tp->t_state &= ~TS_BUSY; 5045406Swnj if (tp->t_state&TS_FLUSH) 5055406Swnj tp->t_state &= ~TS_FLUSH; 506113Sbill else { 5072456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 5082468Swnj /* 5092468Swnj * Do arithmetic in a short to make up 5102468Swnj * for lost 16&17 bits. 5112468Swnj */ 5122605Swnj cntr = addr->dhcar - 5132468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 5143101Swnj ndflush(&tp->t_outq, (int)cntr); 515113Sbill } 516113Sbill if (tp->t_line) 51713Sbill (*linesw[tp->t_line].l_start)(tp); 518113Sbill else 51913Sbill dhstart(tp); 52013Sbill } 52113Sbill } 52213Sbill } 52313Sbill 52413Sbill /* 52513Sbill * Start (restart) transmission on the given DH11 line. 52613Sbill */ 52713Sbill dhstart(tp) 5282395Swnj register struct tty *tp; 52913Sbill { 5302479Swnj register struct dhdevice *addr; 5312468Swnj register int car, dh, unit, nch; 5322395Swnj int s; 53313Sbill 5342468Swnj unit = minor(tp->t_dev); 5352468Swnj dh = unit >> 4; 5362468Swnj unit &= 0xf; 5372479Swnj addr = (struct dhdevice *)tp->t_addr; 5382468Swnj 53913Sbill /* 5402468Swnj * Must hold interrupts in following code to prevent 5412468Swnj * state of the tp from changing. 54213Sbill */ 54313Sbill s = spl5(); 5442468Swnj /* 5452468Swnj * If it's currently active, or delaying, no need to do anything. 5462468Swnj */ 5475406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 54813Sbill goto out; 5492468Swnj /* 5502468Swnj * If there are sleepers, and output has drained below low 5512468Swnj * water mark, wake up the sleepers. 5522468Swnj */ 5535406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5545406Swnj if (tp->t_state&TS_ASLEEP) { 5555406Swnj tp->t_state &= ~TS_ASLEEP; 5565406Swnj wakeup((caddr_t)&tp->t_outq); 5575406Swnj } 5585406Swnj if (tp->t_wsel) { 5595406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5605406Swnj tp->t_wsel = 0; 5615406Swnj tp->t_state &= ~TS_WCOLL; 5625406Swnj } 56313Sbill } 5642468Swnj /* 5652468Swnj * Now restart transmission unless the output queue is 5662468Swnj * empty. 5672468Swnj */ 56813Sbill if (tp->t_outq.c_cc == 0) 56913Sbill goto out; 5703703Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 57113Sbill nch = ndqb(&tp->t_outq, 0); 5722395Swnj else { 57313Sbill nch = ndqb(&tp->t_outq, 0200); 5742468Swnj /* 5752468Swnj * If first thing on queue is a delay process it. 5762468Swnj */ 57713Sbill if (nch == 0) { 57813Sbill nch = getc(&tp->t_outq); 5792468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5805406Swnj tp->t_state |= TS_TIMEOUT; 58113Sbill goto out; 58213Sbill } 58313Sbill } 5842468Swnj /* 5852468Swnj * If characters to transmit, restart transmission. 5862468Swnj */ 58713Sbill if (nch) { 5882468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5892468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5903586Sroot /* 5913586Sroot * The following nonsense with short word 5923586Sroot * is to make sure the dhbar |= word below 5933586Sroot * is done with an interlocking bisw2 instruction. 5943586Sroot */ 5953586Sroot { short word = 1 << unit; 5963586Sroot dhsar[dh] |= word; 5972468Swnj addr->dhcar = car; 59813Sbill addr->dhbcr = -nch; 5993586Sroot addr->dhbar |= word; 6003586Sroot } 6015406Swnj tp->t_state |= TS_BUSY; 60213Sbill } 6032395Swnj out: 60413Sbill splx(s); 60513Sbill } 60613Sbill 60713Sbill /* 6082468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 60913Sbill */ 61013Sbill /*ARGSUSED*/ 61113Sbill dhstop(tp, flag) 6122468Swnj register struct tty *tp; 61313Sbill { 6142479Swnj register struct dhdevice *addr; 6152395Swnj register int unit, s; 61613Sbill 6172479Swnj addr = (struct dhdevice *)tp->t_addr; 6182468Swnj /* 6192468Swnj * Block input/output interrupts while messing with state. 6202468Swnj */ 6212468Swnj s = spl5(); 6225406Swnj if (tp->t_state & TS_BUSY) { 6232468Swnj /* 6242468Swnj * Device is transmitting; stop output 6252468Swnj * by selecting the line and setting the byte 6262468Swnj * count to -1. We will clean up later 6272468Swnj * by examining the address where the dh stopped. 6282468Swnj */ 6292395Swnj unit = minor(tp->t_dev); 6302456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6315406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6325406Swnj tp->t_state |= TS_FLUSH; 633113Sbill addr->dhbcr = -1; 634113Sbill } 63513Sbill splx(s); 63613Sbill } 63713Sbill 638168Sbill /* 639280Sbill * Reset state of driver if UBA reset was necessary. 640280Sbill * Reset the csrl and lpr registers on open lines, and 641280Sbill * restart transmitters. 642280Sbill */ 6432395Swnj dhreset(uban) 6442468Swnj int uban; 645280Sbill { 6462395Swnj register int dh, unit; 647280Sbill register struct tty *tp; 6482974Swnj register struct uba_device *ui; 6492421Skre int i; 650280Sbill 6512421Skre if (dh_ubinfo[uban] == 0) 6522421Skre return; 6532421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6542770Swnj 512+nclist*sizeof (struct cblock), 0); 6552421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6562395Swnj dh = 0; 6572643Swnj for (dh = 0; dh < NDH; dh++) { 6582421Skre ui = dhinfo[dh]; 6592421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6602421Skre continue; 6612924Swnj printf(" dh%d", dh); 6622479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6632479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6642421Skre unit = dh * 16; 6652421Skre for (i = 0; i < 16; i++) { 6662421Skre tp = &dh11[unit]; 6675406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6682421Skre dhparam(unit); 6692479Swnj dmctl(unit, DML_ON, DMSET); 6705406Swnj tp->t_state &= ~TS_BUSY; 6712421Skre dhstart(tp); 6722421Skre } 6732421Skre unit++; 674300Sbill } 675300Sbill } 676300Sbill dhtimer(); 677280Sbill } 6782395Swnj 6792468Swnj /* 6802468Swnj * At software clock interrupt time or after a UNIBUS reset 6812468Swnj * empty all the dh silos. 6822468Swnj */ 6832456Swnj dhtimer() 6842456Swnj { 6852456Swnj register int dh; 6868159Sroot register int s = spl5(); 6872456Swnj 6882643Swnj for (dh = 0; dh < NDH; dh++) 6892456Swnj dhrint(dh); 6908159Sroot splx(s); 6912456Swnj } 6922456Swnj 6932468Swnj /* 6942479Swnj * Turn on the line associated with dh dev. 6952468Swnj */ 6962468Swnj dmopen(dev) 6972468Swnj dev_t dev; 6982468Swnj { 6992468Swnj register struct tty *tp; 7002468Swnj register struct dmdevice *addr; 7012974Swnj register struct uba_device *ui; 7022468Swnj register int unit; 7032468Swnj register int dm; 7043792Swnj int s; 7052468Swnj 7062468Swnj unit = minor(dev); 7072479Swnj dm = unit >> 4; 7082468Swnj tp = &dh11[unit]; 7092566Swnj unit &= 0xf; 7102643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 7112566Swnj (dhsoftCAR[dm]&(1<<unit))) { 7125406Swnj tp->t_state |= TS_CARR_ON; 7132468Swnj return; 7142468Swnj } 7152468Swnj addr = (struct dmdevice *)ui->ui_addr; 7163792Swnj s = spl5(); 7172479Swnj addr->dmcsr &= ~DM_SE; 7182479Swnj while (addr->dmcsr & DM_BUSY) 7192468Swnj ; 7202566Swnj addr->dmcsr = unit; 7212479Swnj addr->dmlstat = DML_ON; 7222479Swnj if (addr->dmlstat&DML_CAR) 7235406Swnj tp->t_state |= TS_CARR_ON; 7243792Swnj addr->dmcsr = DM_IE|DM_SE; 7255406Swnj while ((tp->t_state&TS_CARR_ON)==0) 7262468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7273792Swnj splx(s); 7282468Swnj } 7292468Swnj 7302468Swnj /* 7312468Swnj * Dump control bits into the DM registers. 7322468Swnj */ 7332468Swnj dmctl(dev, bits, how) 7342468Swnj dev_t dev; 7352468Swnj int bits, how; 7362468Swnj { 7372974Swnj register struct uba_device *ui; 7382468Swnj register struct dmdevice *addr; 7392468Swnj register int unit, s; 7402468Swnj int dm; 7412468Swnj 7422468Swnj unit = minor(dev); 7432468Swnj dm = unit >> 4; 7442468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7452468Swnj return; 7462468Swnj addr = (struct dmdevice *)ui->ui_addr; 7472468Swnj s = spl5(); 7482479Swnj addr->dmcsr &= ~DM_SE; 7492479Swnj while (addr->dmcsr & DM_BUSY) 7502468Swnj ; 7512468Swnj addr->dmcsr = unit & 0xf; 7522468Swnj switch(how) { 7532468Swnj case DMSET: 7542468Swnj addr->dmlstat = bits; 7552468Swnj break; 7562468Swnj case DMBIS: 7572468Swnj addr->dmlstat |= bits; 7582468Swnj break; 7592468Swnj case DMBIC: 7602468Swnj addr->dmlstat &= ~bits; 7612468Swnj break; 7622468Swnj } 7633792Swnj addr->dmcsr = DM_IE|DM_SE; 7642468Swnj splx(s); 7652468Swnj } 7662468Swnj 7672468Swnj /* 7682468Swnj * DM11 interrupt; deal with carrier transitions. 7692468Swnj */ 7702468Swnj dmintr(dm) 7712468Swnj register int dm; 7722468Swnj { 7732974Swnj register struct uba_device *ui; 7742468Swnj register struct tty *tp; 7752468Swnj register struct dmdevice *addr; 7762468Swnj 7772468Swnj ui = dminfo[dm]; 7782479Swnj if (ui == 0) 7792479Swnj return; 7802468Swnj addr = (struct dmdevice *)ui->ui_addr; 7813997Sroot if (addr->dmcsr&DM_DONE) { 7823997Sroot if (addr->dmcsr&DM_CF) { 7833997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7843997Sroot wakeup((caddr_t)&tp->t_rawq); 7855406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7863997Sroot (tp->t_local&LMDMBUF)) { 7873997Sroot if (addr->dmlstat & DML_CAR) { 7885406Swnj tp->t_state &= ~TS_TTSTOP; 7893997Sroot ttstart(tp); 7905406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7915406Swnj tp->t_state |= TS_TTSTOP; 7923997Sroot dhstop(tp, 0); 7933997Sroot } 7943997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7955406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7963997Sroot (tp->t_local&LNOHANG)==0) { 7973997Sroot gsignal(tp->t_pgrp, SIGHUP); 7983997Sroot gsignal(tp->t_pgrp, SIGCONT); 7993997Sroot addr->dmlstat = 0; 8003997Sroot flushtty(tp, FREAD|FWRITE); 8013997Sroot } 8025406Swnj tp->t_state &= ~TS_CARR_ON; 8033997Sroot } else 8045406Swnj tp->t_state |= TS_CARR_ON; 8053997Sroot } 8063997Sroot addr->dmcsr = DM_IE|DM_SE; 8072468Swnj } 8082468Swnj } 8092625Swnj #endif 810