1*6615Ssam /* dh.c 4.44 82/05/04 */ 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" 2413Sbill 252468Swnj /* 262479Swnj * Definition of the driver for the auto-configuration program. 272479Swnj * There is one definition for the dh and one for the dm. 282468Swnj */ 292605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 302974Swnj struct uba_device *dhinfo[NDH]; 312395Swnj u_short dhstd[] = { 0 }; 322395Swnj struct uba_driver dhdriver = 332605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 342395Swnj 352605Swnj int dmprobe(), dmattach(), dmintr(); 362974Swnj struct uba_device *dminfo[NDH]; 372479Swnj u_short dmstd[] = { 0 }; 382479Swnj struct uba_driver dmdriver = 392605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4013Sbill 412479Swnj struct dhdevice 422479Swnj { 432479Swnj union { 442479Swnj short dhcsr; /* control-status register */ 452479Swnj char dhcsrl; /* low byte for line select */ 462479Swnj } un; 472479Swnj short dhrcr; /* receive character register */ 482479Swnj short dhlpr; /* line parameter register */ 492479Swnj u_short dhcar; /* current address register */ 502479Swnj short dhbcr; /* byte count register */ 512479Swnj u_short dhbar; /* buffer active register */ 522479Swnj short dhbreak; /* break control register */ 532479Swnj short dhsilo; /* silo status register */ 542479Swnj }; 5513Sbill 56*6615Ssam #ifndef PORTSELECTOR 57*6615Ssam #define ISPEED B300 58*6615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 59*6615Ssam #else 60*6615Ssam #define ISPEED B4800 61*6615Ssam #define IFLAGS (EVENP|ODDP) 62*6615Ssam #endif 63*6615Ssam 642456Swnj /* Bits in dhcsr */ 652456Swnj #define DH_TI 0100000 /* transmit interrupt */ 662456Swnj #define DH_SI 0040000 /* storage interrupt */ 672456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 682456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 692456Swnj #define DH_MC 0004000 /* master clear */ 702456Swnj #define DH_NXM 0002000 /* non-existant memory */ 712456Swnj #define DH_MM 0001000 /* maintenance mode */ 722456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 732456Swnj #define DH_RI 0000200 /* receiver interrupt */ 742456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 7513Sbill 762479Swnj /* Bits in dhlpr */ 772479Swnj #define BITS6 01 782479Swnj #define BITS7 02 792479Swnj #define BITS8 03 802479Swnj #define TWOSB 04 812479Swnj #define PENABLE 020 822479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 832479Swnj #define OPAR 040 842479Swnj #define HDUPLX 040000 852479Swnj 862456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 872456Swnj 882456Swnj /* Bits in dhrcr */ 892479Swnj #define DH_PE 0010000 /* parity error */ 902479Swnj #define DH_FE 0020000 /* framing error */ 912479Swnj #define DH_DO 0040000 /* data overrun */ 922456Swnj 932479Swnj struct dmdevice 942479Swnj { 952479Swnj short dmcsr; /* control status register */ 962479Swnj short dmlstat; /* line status register */ 972479Swnj short dmpad1[2]; 982479Swnj }; 992479Swnj 1002479Swnj /* bits in dm csr */ 1012479Swnj #define DM_RF 0100000 /* ring flag */ 1022479Swnj #define DM_CF 0040000 /* carrier flag */ 1032479Swnj #define DM_CTS 0020000 /* clear to send */ 1042479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 1052479Swnj #define DM_CS 0004000 /* clear scan */ 1062479Swnj #define DM_CM 0002000 /* clear multiplexor */ 1072479Swnj #define DM_MM 0001000 /* maintenance mode */ 1082479Swnj #define DM_STP 0000400 /* step */ 1092479Swnj #define DM_DONE 0000200 /* scanner is done */ 1102479Swnj #define DM_IE 0000100 /* interrupt enable */ 1112479Swnj #define DM_SE 0000040 /* scan enable */ 1122479Swnj #define DM_BUSY 0000020 /* scan busy */ 1132479Swnj 1142479Swnj /* bits in dm lsr */ 1152479Swnj #define DML_RNG 0000200 /* ring */ 1162479Swnj #define DML_CAR 0000100 /* carrier detect */ 1172479Swnj #define DML_CTS 0000040 /* clear to send */ 1182479Swnj #define DML_SR 0000020 /* secondary receive */ 1192479Swnj #define DML_ST 0000010 /* secondary transmit */ 1202479Swnj #define DML_RTS 0000004 /* request to send */ 1212479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1222479Swnj #define DML_LE 0000001 /* line enable */ 1232479Swnj 1243792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1252479Swnj #define DML_OFF (DML_LE) 1262479Swnj 12713Sbill /* 1282479Swnj * Local variables for the driver 12913Sbill */ 1302643Swnj short dhsar[NDH]; /* software copy of last bar */ 1312643Swnj short dhsoftCAR[NDH]; 13213Sbill 1332643Swnj struct tty dh11[NDH*16]; 1342643Swnj int ndh11 = NDH*16; 1352479Swnj int dhact; /* mask of active dh's */ 1362479Swnj int dhstart(), ttrstrt(); 13713Sbill 1382479Swnj /* 1392479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1402479Swnj * The UBACVT macro converts a clist space address for unibus uban 1412479Swnj * into an i/o space address for the DMA routine. 1422479Swnj */ 1432479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1442479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1452479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 14613Sbill 1472456Swnj /* 1482456Swnj * Routine for configuration to force a dh to interrupt. 1492456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1502456Swnj */ 1512468Swnj /*ARGSUSED*/ 1522605Swnj dhprobe(reg) 1532395Swnj caddr_t reg; 1542395Swnj { 1552468Swnj register int br, cvec; /* these are ``value-result'' */ 1562479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1572395Swnj 1582605Swnj #ifdef lint 1592605Swnj br = 0; cvec = br; br = cvec; 1604932Swnj dhrint(0); dhxint(0); 1612605Swnj #endif 1622696Swnj #ifndef notdef 1632566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1646380Swnj DELAY(1000); 1652566Swnj dhaddr->un.dhcsr = 0; 1662566Swnj #else 1672456Swnj dhaddr->un.dhcsr = DH_TIE; 1682456Swnj DELAY(5); 1692456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1702421Skre dhaddr->dhbcr = -1; 1712456Swnj dhaddr->dhcar = 0; 1722421Skre dhaddr->dhbar = 1; 1732456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1742421Skre dhaddr->un.dhcsr = 0; 1752456Swnj if (cvec && cvec != 0x200) 1762456Swnj cvec -= 4; /* transmit -> receive */ 1772482Swnj #endif 1782456Swnj return (1); 1792395Swnj } 1802395Swnj 1812456Swnj /* 1822605Swnj * Routine called to attach a dh. 1832456Swnj */ 1842605Swnj dhattach(ui) 1852974Swnj struct uba_device *ui; 1862395Swnj { 1872395Swnj 1882566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1892395Swnj } 1902395Swnj 19113Sbill /* 1922479Swnj * Configuration routine to cause a dm to interrupt. 1932479Swnj */ 1942605Swnj dmprobe(reg) 1952605Swnj caddr_t reg; 1962479Swnj { 1972479Swnj register int br, vec; /* value-result */ 1982605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1992479Swnj 2002605Swnj #ifdef lint 2013101Swnj br = 0; vec = br; br = vec; 2026185Ssam dmintr(0); 2032605Swnj #endif 2042479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 2052479Swnj DELAY(20); 2062479Swnj dmaddr->dmcsr = 0; 2072605Swnj return (1); 2082479Swnj } 2092479Swnj 2102605Swnj /*ARGSUSED*/ 2112605Swnj dmattach(ui) 2122974Swnj struct uba_device *ui; 2132479Swnj { 2142479Swnj 2152479Swnj /* no local state to set up */ 2162479Swnj } 2172479Swnj 2182479Swnj /* 2192468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2202468Swnj * is the first dh on this uba. Turn on this dh if this is 2212468Swnj * the first use of it. Also do a dmopen to wait for carrier. 22213Sbill */ 22313Sbill /*ARGSUSED*/ 22413Sbill dhopen(dev, flag) 2252395Swnj dev_t dev; 22613Sbill { 22713Sbill register struct tty *tp; 2282395Swnj register int unit, dh; 2292479Swnj register struct dhdevice *addr; 2302974Swnj register struct uba_device *ui; 23113Sbill int s; 23213Sbill 2332395Swnj unit = minor(dev); 2342395Swnj dh = unit >> 4; 2352643Swnj if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 23613Sbill u.u_error = ENXIO; 23713Sbill return; 23813Sbill } 2392395Swnj tp = &dh11[unit]; 2405406Swnj if (tp->t_state&TS_XCLUDE && u.u_uid!=0) { 2412468Swnj u.u_error = EBUSY; 2422468Swnj return; 2432468Swnj } 2442479Swnj addr = (struct dhdevice *)ui->ui_addr; 24513Sbill tp->t_addr = (caddr_t)addr; 24613Sbill tp->t_oproc = dhstart; 2475406Swnj tp->t_state |= TS_WOPEN; 2482468Swnj /* 2492468Swnj * While setting up state for this uba and this dh, 2502468Swnj * block uba resets which can clear the state. 2512468Swnj */ 2522468Swnj s = spl5(); 2532421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 254717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2552395Swnj dh_ubinfo[ui->ui_ubanum] = 2562421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2572770Swnj 512+nclist*sizeof(struct cblock), 0); 2582456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 25913Sbill } 2602456Swnj if ((dhact&(1<<dh)) == 0) { 2612456Swnj addr->un.dhcsr |= DH_IE; 2622468Swnj dhact |= (1<<dh); 2632456Swnj addr->dhsilo = 16; 2642456Swnj } 26513Sbill splx(s); 2662468Swnj /* 2672468Swnj * If this is first open, initialze tty state to default. 2682468Swnj */ 2695406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 27013Sbill ttychars(tp); 271*6615Ssam #ifndef PORTSELECTOR 272168Sbill if (tp->t_ispeed == 0) { 273*6615Ssam #endif 274*6615Ssam tp->t_ispeed = ISPEED; 275*6615Ssam tp->t_ospeed = ISPEED; 276*6615Ssam tp->t_flags = IFLAGS; 277*6615Ssam #ifndef PORTSELECTOR 278168Sbill } 279*6615Ssam #endif 2802395Swnj dhparam(unit); 28113Sbill } 2822468Swnj /* 2832468Swnj * Wait for carrier, then process line discipline specific open. 2842468Swnj */ 28513Sbill dmopen(dev); 2862395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 28713Sbill } 28813Sbill 28913Sbill /* 2902468Swnj * Close a DH11 line, turning off the DM11. 29113Sbill */ 29213Sbill /*ARGSUSED*/ 29313Sbill dhclose(dev, flag) 2942395Swnj dev_t dev; 2952395Swnj int flag; 29613Sbill { 29713Sbill register struct tty *tp; 2982395Swnj register unit; 29913Sbill 3002395Swnj unit = minor(dev); 3012395Swnj tp = &dh11[unit]; 30213Sbill (*linesw[tp->t_line].l_close)(tp); 3032479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 3045406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3052479Swnj dmctl(unit, DML_OFF, DMSET); 30613Sbill ttyclose(tp); 30713Sbill } 30813Sbill 30913Sbill dhread(dev) 3102395Swnj dev_t dev; 31113Sbill { 3122395Swnj register struct tty *tp; 31313Sbill 3142395Swnj tp = &dh11[minor(dev)]; 31513Sbill (*linesw[tp->t_line].l_read)(tp); 31613Sbill } 31713Sbill 31813Sbill dhwrite(dev) 3192395Swnj dev_t dev; 32013Sbill { 3212395Swnj register struct tty *tp; 32213Sbill 3232395Swnj tp = &dh11[minor(dev)]; 32413Sbill (*linesw[tp->t_line].l_write)(tp); 32513Sbill } 32613Sbill 32713Sbill /* 32813Sbill * DH11 receiver interrupt. 32913Sbill */ 3302395Swnj dhrint(dh) 3312395Swnj int dh; 33213Sbill { 33313Sbill register struct tty *tp; 3342395Swnj register c; 3352479Swnj register struct dhdevice *addr; 336117Sbill register struct tty *tp0; 3372974Swnj register struct uba_device *ui; 3382924Swnj int overrun = 0; 33913Sbill 3402395Swnj ui = dhinfo[dh]; 3412479Swnj if (ui == 0 || ui->ui_alive == 0) 3422479Swnj return; 3432479Swnj addr = (struct dhdevice *)ui->ui_addr; 3442468Swnj tp0 = &dh11[dh<<4]; 3452468Swnj /* 3462468Swnj * Loop fetching characters from the silo for this 3472468Swnj * dh until there are no more in the silo. 3482468Swnj */ 3492468Swnj while ((c = addr->dhrcr) < 0) { 3502468Swnj tp = tp0 + ((c>>8)&0xf); 351*6615Ssam #ifndef PORTSELECTOR 3525406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 353*6615Ssam #else 354*6615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 355*6615Ssam #endif 35613Sbill wakeup((caddr_t)tp); 35713Sbill continue; 35813Sbill } 3592468Swnj if (c & DH_PE) 36013Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 36113Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 36213Sbill continue; 3632924Swnj if ((c & DH_DO) && overrun == 0) { 3642924Swnj printf("dh%d: silo overflow\n", dh); 3652924Swnj overrun = 1; 3662924Swnj } 3672468Swnj if (c & DH_FE) 3682468Swnj /* 3692468Swnj * At framing error (break) generate 3702468Swnj * a null (in raw mode, for getty), or a 3712468Swnj * interrupt (in cooked/cbreak mode). 3722468Swnj */ 37313Sbill if (tp->t_flags&RAW) 3742468Swnj c = 0; 37513Sbill else 376184Sbill c = tun.t_intrc; 3772730Swnj #if NBK > 0 378139Sbill if (tp->t_line == NETLDISC) { 379117Sbill c &= 0177; 380168Sbill BKINPUT(c, tp); 381117Sbill } else 3822730Swnj #endif 3832468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 38413Sbill } 38513Sbill } 38613Sbill 38713Sbill /* 3882468Swnj * Ioctl for DH11. 38913Sbill */ 39013Sbill /*ARGSUSED*/ 39113Sbill dhioctl(dev, cmd, addr, flag) 3922395Swnj caddr_t addr; 39313Sbill { 39413Sbill register struct tty *tp; 3952395Swnj register unit = minor(dev); 39613Sbill 3972395Swnj tp = &dh11[unit]; 398113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 3992468Swnj if (cmd == 0) 400113Sbill return; 4011895Swnj if (ttioctl(tp, cmd, addr, flag)) { 4022468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 4032395Swnj dhparam(unit); 404168Sbill } else switch(cmd) { 405168Sbill case TIOCSBRK: 4062479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 407168Sbill break; 408168Sbill case TIOCCBRK: 4092479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 410168Sbill break; 411168Sbill case TIOCSDTR: 4122479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 413168Sbill break; 414168Sbill case TIOCCDTR: 4152479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 416168Sbill break; 417168Sbill default: 41813Sbill u.u_error = ENOTTY; 419168Sbill } 42013Sbill } 42113Sbill 42213Sbill /* 42313Sbill * Set parameters from open or stty into the DH hardware 42413Sbill * registers. 42513Sbill */ 4262395Swnj dhparam(unit) 4272395Swnj register int unit; 42813Sbill { 42913Sbill register struct tty *tp; 4302479Swnj register struct dhdevice *addr; 4312395Swnj register int lpar; 432300Sbill int s; 43313Sbill 4342395Swnj tp = &dh11[unit]; 4352479Swnj addr = (struct dhdevice *)tp->t_addr; 4362468Swnj /* 4372468Swnj * Block interrupts so parameters will be set 4382468Swnj * before the line interrupts. 4392468Swnj */ 440300Sbill s = spl5(); 4412468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 44213Sbill if ((tp->t_ispeed)==0) { 4435406Swnj tp->t_state |= TS_HUPCLS; 4442479Swnj dmctl(unit, DML_OFF, DMSET); 44513Sbill return; 44613Sbill } 4472395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4482468Swnj if ((tp->t_ispeed) == B134) 4492395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4502312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4512395Swnj lpar |= BITS8; 45213Sbill else 4532395Swnj lpar |= BITS7|PENABLE; 45413Sbill if ((tp->t_flags&EVENP) == 0) 4552395Swnj lpar |= OPAR; 4562468Swnj if ((tp->t_ospeed) == B110) 4572395Swnj lpar |= TWOSB; 4582395Swnj addr->dhlpr = lpar; 459300Sbill splx(s); 46013Sbill } 46113Sbill 46213Sbill /* 46313Sbill * DH11 transmitter interrupt. 46413Sbill * Restart each line which used to be active but has 46513Sbill * terminated transmission since the last interrupt. 46613Sbill */ 4672395Swnj dhxint(dh) 4682395Swnj int dh; 46913Sbill { 47013Sbill register struct tty *tp; 4712479Swnj register struct dhdevice *addr; 47213Sbill short ttybit, bar, *sbar; 4732974Swnj register struct uba_device *ui; 4742468Swnj register int unit; 4752605Swnj u_short cntr; 47613Sbill 4772395Swnj ui = dhinfo[dh]; 4782479Swnj addr = (struct dhdevice *)ui->ui_addr; 4792456Swnj if (addr->un.dhcsr & DH_NXM) { 4802456Swnj addr->un.dhcsr |= DH_CNI; 4812924Swnj printf("dh%d: NXM\n", dh); 482105Sbill } 4832395Swnj sbar = &dhsar[dh]; 48413Sbill bar = *sbar & ~addr->dhbar; 4852395Swnj unit = dh * 16; ttybit = 1; 4862468Swnj addr->un.dhcsr &= (short)~DH_TI; 4872468Swnj for (; bar; unit++, ttybit <<= 1) { 4882468Swnj if (bar & ttybit) { 48913Sbill *sbar &= ~ttybit; 49013Sbill bar &= ~ttybit; 4912395Swnj tp = &dh11[unit]; 4925406Swnj tp->t_state &= ~TS_BUSY; 4935406Swnj if (tp->t_state&TS_FLUSH) 4945406Swnj tp->t_state &= ~TS_FLUSH; 495113Sbill else { 4962456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4972468Swnj /* 4982468Swnj * Do arithmetic in a short to make up 4992468Swnj * for lost 16&17 bits. 5002468Swnj */ 5012605Swnj cntr = addr->dhcar - 5022468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 5033101Swnj ndflush(&tp->t_outq, (int)cntr); 504113Sbill } 505113Sbill if (tp->t_line) 50613Sbill (*linesw[tp->t_line].l_start)(tp); 507113Sbill else 50813Sbill dhstart(tp); 50913Sbill } 51013Sbill } 51113Sbill } 51213Sbill 51313Sbill /* 51413Sbill * Start (restart) transmission on the given DH11 line. 51513Sbill */ 51613Sbill dhstart(tp) 5172395Swnj register struct tty *tp; 51813Sbill { 5192479Swnj register struct dhdevice *addr; 5202468Swnj register int car, dh, unit, nch; 5212395Swnj int s; 52213Sbill 5232468Swnj unit = minor(tp->t_dev); 5242468Swnj dh = unit >> 4; 5252468Swnj unit &= 0xf; 5262479Swnj addr = (struct dhdevice *)tp->t_addr; 5272468Swnj 52813Sbill /* 5292468Swnj * Must hold interrupts in following code to prevent 5302468Swnj * state of the tp from changing. 53113Sbill */ 53213Sbill s = spl5(); 5332468Swnj /* 5342468Swnj * If it's currently active, or delaying, no need to do anything. 5352468Swnj */ 5365406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 53713Sbill goto out; 5382468Swnj /* 5392468Swnj * If there are sleepers, and output has drained below low 5402468Swnj * water mark, wake up the sleepers. 5412468Swnj */ 5425406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5435406Swnj if (tp->t_state&TS_ASLEEP) { 5445406Swnj tp->t_state &= ~TS_ASLEEP; 5455406Swnj wakeup((caddr_t)&tp->t_outq); 5465406Swnj } 5475406Swnj if (tp->t_wsel) { 5485406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5495406Swnj tp->t_wsel = 0; 5505406Swnj tp->t_state &= ~TS_WCOLL; 5515406Swnj } 55213Sbill } 5532468Swnj /* 5542468Swnj * Now restart transmission unless the output queue is 5552468Swnj * empty. 5562468Swnj */ 55713Sbill if (tp->t_outq.c_cc == 0) 55813Sbill goto out; 5593703Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 56013Sbill nch = ndqb(&tp->t_outq, 0); 5612395Swnj else { 56213Sbill nch = ndqb(&tp->t_outq, 0200); 5632468Swnj /* 5642468Swnj * If first thing on queue is a delay process it. 5652468Swnj */ 56613Sbill if (nch == 0) { 56713Sbill nch = getc(&tp->t_outq); 5682468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5695406Swnj tp->t_state |= TS_TIMEOUT; 57013Sbill goto out; 57113Sbill } 57213Sbill } 5732468Swnj /* 5742468Swnj * If characters to transmit, restart transmission. 5752468Swnj */ 57613Sbill if (nch) { 5772468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5782468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5793586Sroot /* 5803586Sroot * The following nonsense with short word 5813586Sroot * is to make sure the dhbar |= word below 5823586Sroot * is done with an interlocking bisw2 instruction. 5833586Sroot */ 5843586Sroot { short word = 1 << unit; 5853586Sroot dhsar[dh] |= word; 5862468Swnj addr->dhcar = car; 58713Sbill addr->dhbcr = -nch; 5883586Sroot addr->dhbar |= word; 5893586Sroot } 5905406Swnj tp->t_state |= TS_BUSY; 59113Sbill } 5922395Swnj out: 59313Sbill splx(s); 59413Sbill } 59513Sbill 59613Sbill /* 5972468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 59813Sbill */ 59913Sbill /*ARGSUSED*/ 60013Sbill dhstop(tp, flag) 6012468Swnj register struct tty *tp; 60213Sbill { 6032479Swnj register struct dhdevice *addr; 6042395Swnj register int unit, s; 60513Sbill 6062479Swnj addr = (struct dhdevice *)tp->t_addr; 6072468Swnj /* 6082468Swnj * Block input/output interrupts while messing with state. 6092468Swnj */ 6102468Swnj s = spl5(); 6115406Swnj if (tp->t_state & TS_BUSY) { 6122468Swnj /* 6132468Swnj * Device is transmitting; stop output 6142468Swnj * by selecting the line and setting the byte 6152468Swnj * count to -1. We will clean up later 6162468Swnj * by examining the address where the dh stopped. 6172468Swnj */ 6182395Swnj unit = minor(tp->t_dev); 6192456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6205406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6215406Swnj tp->t_state |= TS_FLUSH; 622113Sbill addr->dhbcr = -1; 623113Sbill } 62413Sbill splx(s); 62513Sbill } 62613Sbill 627168Sbill /* 628280Sbill * Reset state of driver if UBA reset was necessary. 629280Sbill * Reset the csrl and lpr registers on open lines, and 630280Sbill * restart transmitters. 631280Sbill */ 6322395Swnj dhreset(uban) 6332468Swnj int uban; 634280Sbill { 6352395Swnj register int dh, unit; 636280Sbill register struct tty *tp; 6372974Swnj register struct uba_device *ui; 6382421Skre int i; 639280Sbill 6402421Skre if (dh_ubinfo[uban] == 0) 6412421Skre return; 6422421Skre ubarelse(uban, &dh_ubinfo[uban]); 6432421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6442770Swnj 512+nclist*sizeof (struct cblock), 0); 6452421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6462395Swnj dh = 0; 6472643Swnj for (dh = 0; dh < NDH; dh++) { 6482421Skre ui = dhinfo[dh]; 6492421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6502421Skre continue; 6512924Swnj printf(" dh%d", dh); 6522479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6532479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6542421Skre unit = dh * 16; 6552421Skre for (i = 0; i < 16; i++) { 6562421Skre tp = &dh11[unit]; 6575406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6582421Skre dhparam(unit); 6592479Swnj dmctl(unit, DML_ON, DMSET); 6605406Swnj tp->t_state &= ~TS_BUSY; 6612421Skre dhstart(tp); 6622421Skre } 6632421Skre unit++; 664300Sbill } 665300Sbill } 666300Sbill dhtimer(); 667280Sbill } 6682395Swnj 6692468Swnj /* 6702468Swnj * At software clock interrupt time or after a UNIBUS reset 6712468Swnj * empty all the dh silos. 6722468Swnj */ 6732456Swnj dhtimer() 6742456Swnj { 6752456Swnj register int dh; 6762456Swnj 6772643Swnj for (dh = 0; dh < NDH; dh++) 6782456Swnj dhrint(dh); 6792456Swnj } 6802456Swnj 6812468Swnj /* 6822479Swnj * Turn on the line associated with dh dev. 6832468Swnj */ 6842468Swnj dmopen(dev) 6852468Swnj dev_t dev; 6862468Swnj { 6872468Swnj register struct tty *tp; 6882468Swnj register struct dmdevice *addr; 6892974Swnj register struct uba_device *ui; 6902468Swnj register int unit; 6912468Swnj register int dm; 6923792Swnj int s; 6932468Swnj 6942468Swnj unit = minor(dev); 6952479Swnj dm = unit >> 4; 6962468Swnj tp = &dh11[unit]; 6972566Swnj unit &= 0xf; 6982643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 6992566Swnj (dhsoftCAR[dm]&(1<<unit))) { 7005406Swnj tp->t_state |= TS_CARR_ON; 7012468Swnj return; 7022468Swnj } 7032468Swnj addr = (struct dmdevice *)ui->ui_addr; 7043792Swnj s = spl5(); 7052479Swnj addr->dmcsr &= ~DM_SE; 7062479Swnj while (addr->dmcsr & DM_BUSY) 7072468Swnj ; 7082566Swnj addr->dmcsr = unit; 7092479Swnj addr->dmlstat = DML_ON; 7102479Swnj if (addr->dmlstat&DML_CAR) 7115406Swnj tp->t_state |= TS_CARR_ON; 7123792Swnj addr->dmcsr = DM_IE|DM_SE; 7135406Swnj while ((tp->t_state&TS_CARR_ON)==0) 7142468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7153792Swnj splx(s); 7162468Swnj } 7172468Swnj 7182468Swnj /* 7192468Swnj * Dump control bits into the DM registers. 7202468Swnj */ 7212468Swnj dmctl(dev, bits, how) 7222468Swnj dev_t dev; 7232468Swnj int bits, how; 7242468Swnj { 7252974Swnj register struct uba_device *ui; 7262468Swnj register struct dmdevice *addr; 7272468Swnj register int unit, s; 7282468Swnj int dm; 7292468Swnj 7302468Swnj unit = minor(dev); 7312468Swnj dm = unit >> 4; 7322468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7332468Swnj return; 7342468Swnj addr = (struct dmdevice *)ui->ui_addr; 7352468Swnj s = spl5(); 7362479Swnj addr->dmcsr &= ~DM_SE; 7372479Swnj while (addr->dmcsr & DM_BUSY) 7382468Swnj ; 7392468Swnj addr->dmcsr = unit & 0xf; 7402468Swnj switch(how) { 7412468Swnj case DMSET: 7422468Swnj addr->dmlstat = bits; 7432468Swnj break; 7442468Swnj case DMBIS: 7452468Swnj addr->dmlstat |= bits; 7462468Swnj break; 7472468Swnj case DMBIC: 7482468Swnj addr->dmlstat &= ~bits; 7492468Swnj break; 7502468Swnj } 7513792Swnj addr->dmcsr = DM_IE|DM_SE; 7522468Swnj splx(s); 7532468Swnj } 7542468Swnj 7552468Swnj /* 7562468Swnj * DM11 interrupt; deal with carrier transitions. 7572468Swnj */ 7582468Swnj dmintr(dm) 7592468Swnj register int dm; 7602468Swnj { 7612974Swnj register struct uba_device *ui; 7622468Swnj register struct tty *tp; 7632468Swnj register struct dmdevice *addr; 7642468Swnj 7652468Swnj ui = dminfo[dm]; 7662479Swnj if (ui == 0) 7672479Swnj return; 7682468Swnj addr = (struct dmdevice *)ui->ui_addr; 7693997Sroot if (addr->dmcsr&DM_DONE) { 7703997Sroot if (addr->dmcsr&DM_CF) { 7713997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7723997Sroot wakeup((caddr_t)&tp->t_rawq); 7735406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7743997Sroot (tp->t_local&LMDMBUF)) { 7753997Sroot if (addr->dmlstat & DML_CAR) { 7765406Swnj tp->t_state &= ~TS_TTSTOP; 7773997Sroot ttstart(tp); 7785406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7795406Swnj tp->t_state |= TS_TTSTOP; 7803997Sroot dhstop(tp, 0); 7813997Sroot } 7823997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7835406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7843997Sroot (tp->t_local&LNOHANG)==0) { 7853997Sroot gsignal(tp->t_pgrp, SIGHUP); 7863997Sroot gsignal(tp->t_pgrp, SIGCONT); 7873997Sroot addr->dmlstat = 0; 7883997Sroot flushtty(tp, FREAD|FWRITE); 7893997Sroot } 7905406Swnj tp->t_state &= ~TS_CARR_ON; 7913997Sroot } else 7925406Swnj tp->t_state |= TS_CARR_ON; 7933997Sroot } 7943997Sroot addr->dmcsr = DM_IE|DM_SE; 7952468Swnj } 7962468Swnj } 7972625Swnj #endif 798