1*2479Swnj /* dh.c 4.17 81/02/18 */ 213Sbill 31934Swnj #include "dh.h" 41561Sbill #if NDH11 > 0 52456Swnj #define DELAY(i) { register int j = i; while (--j > 0); } 613Sbill /* 7*2479Swnj * DH-11/DM-11 driver 813Sbill */ 913Sbill #include "../h/param.h" 1013Sbill #include "../h/conf.h" 1113Sbill #include "../h/dir.h" 1213Sbill #include "../h/user.h" 1313Sbill #include "../h/tty.h" 1413Sbill #include "../h/map.h" 1513Sbill #include "../h/pte.h" 162395Swnj #include "../h/buf.h" 1713Sbill #include "../h/uba.h" 18113Sbill #include "../h/bk.h" 191561Sbill #include "../h/clist.h" 201786Sbill #include "../h/mx.h" 212468Swnj #include "../h/file.h" 2213Sbill 232468Swnj /* 24*2479Swnj * Definition of the driver for the auto-configuration program. 25*2479Swnj * There is one definition for the dh and one for the dm. 262468Swnj */ 272395Swnj int dhcntrlr(), dhslave(), dhrint(), dhxint(); 282395Swnj struct uba_dinfo *dhinfo[NDH11]; 292395Swnj u_short dhstd[] = { 0 }; 302395Swnj struct uba_driver dhdriver = 31*2479Swnj { dhcntrlr, dhslave, 0, 0, dhstd, "dh11", dhinfo }; 322395Swnj 33*2479Swnj int dmcntrlr(), dmslave(), dmintr(); 34*2479Swnj struct uba_dinfo *dminfo[NDH11]; 35*2479Swnj u_short dmstd[] = { 0 }; 36*2479Swnj struct uba_driver dmdriver = 37*2479Swnj { dmcntrlr, dmslave, 0, 0, dmstd, "dm11", dminfo }; 3813Sbill 39*2479Swnj struct dhdevice 40*2479Swnj { 41*2479Swnj union { 42*2479Swnj short dhcsr; /* control-status register */ 43*2479Swnj char dhcsrl; /* low byte for line select */ 44*2479Swnj } un; 45*2479Swnj short dhrcr; /* receive character register */ 46*2479Swnj short dhlpr; /* line parameter register */ 47*2479Swnj u_short dhcar; /* current address register */ 48*2479Swnj short dhbcr; /* byte count register */ 49*2479Swnj u_short dhbar; /* buffer active register */ 50*2479Swnj short dhbreak; /* break control register */ 51*2479Swnj short dhsilo; /* silo status register */ 52*2479Swnj }; 5313Sbill 542456Swnj /* Bits in dhcsr */ 552456Swnj #define DH_TI 0100000 /* transmit interrupt */ 562456Swnj #define DH_SI 0040000 /* storage interrupt */ 572456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 582456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 592456Swnj #define DH_MC 0004000 /* master clear */ 602456Swnj #define DH_NXM 0002000 /* non-existant memory */ 612456Swnj #define DH_MM 0001000 /* maintenance mode */ 622456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 632456Swnj #define DH_RI 0000200 /* receiver interrupt */ 642456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 6513Sbill 66*2479Swnj /* Bits in dhlpr */ 67*2479Swnj #define BITS6 01 68*2479Swnj #define BITS7 02 69*2479Swnj #define BITS8 03 70*2479Swnj #define TWOSB 04 71*2479Swnj #define PENABLE 020 72*2479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 73*2479Swnj #define OPAR 040 74*2479Swnj #define HDUPLX 040000 75*2479Swnj 762456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 772456Swnj 782456Swnj /* Bits in dhrcr */ 79*2479Swnj #define DH_PE 0010000 /* parity error */ 80*2479Swnj #define DH_FE 0020000 /* framing error */ 81*2479Swnj #define DH_DO 0040000 /* data overrun */ 822456Swnj 83*2479Swnj struct dmdevice 84*2479Swnj { 85*2479Swnj short dmcsr; /* control status register */ 86*2479Swnj short dmlstat; /* line status register */ 87*2479Swnj short dmpad1[2]; 88*2479Swnj }; 89*2479Swnj 90*2479Swnj /* bits in dm csr */ 91*2479Swnj #define DM_RF 0100000 /* ring flag */ 92*2479Swnj #define DM_CF 0040000 /* carrier flag */ 93*2479Swnj #define DM_CTS 0020000 /* clear to send */ 94*2479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 95*2479Swnj #define DM_CS 0004000 /* clear scan */ 96*2479Swnj #define DM_CM 0002000 /* clear multiplexor */ 97*2479Swnj #define DM_MM 0001000 /* maintenance mode */ 98*2479Swnj #define DM_STP 0000400 /* step */ 99*2479Swnj #define DM_DONE 0000200 /* scanner is done */ 100*2479Swnj #define DM_IE 0000100 /* interrupt enable */ 101*2479Swnj #define DM_SE 0000040 /* scan enable */ 102*2479Swnj #define DM_BUSY 0000020 /* scan busy */ 103*2479Swnj 104*2479Swnj /* bits in dm lsr */ 105*2479Swnj #define DML_RNG 0000200 /* ring */ 106*2479Swnj #define DML_CAR 0000100 /* carrier detect */ 107*2479Swnj #define DML_CTS 0000040 /* clear to send */ 108*2479Swnj #define DML_SR 0000020 /* secondary receive */ 109*2479Swnj #define DML_ST 0000010 /* secondary transmit */ 110*2479Swnj #define DML_RTS 0000004 /* request to send */ 111*2479Swnj #define DML_DTR 0000002 /* data terminal ready */ 112*2479Swnj #define DML_LE 0000001 /* line enable */ 113*2479Swnj 114*2479Swnj #define DML_ON (DML_DTR|DML_LE) 115*2479Swnj #define DML_OFF (DML_LE) 116*2479Swnj 11713Sbill /* 118*2479Swnj * Local variables for the driver 11913Sbill */ 120*2479Swnj short dhsar[NDH11]; /* software copy of last bar */ 12113Sbill 122*2479Swnj struct tty dh11[NDH11*16]; 123*2479Swnj int ndh11 = NDH11*16; 124*2479Swnj int dhact; /* mask of active dh's */ 125*2479Swnj int dhstart(), ttrstrt(); 12613Sbill 127*2479Swnj /* 128*2479Swnj * The clist space is mapped by the driver onto each UNIBUS. 129*2479Swnj * The UBACVT macro converts a clist space address for unibus uban 130*2479Swnj * into an i/o space address for the DMA routine. 131*2479Swnj */ 132*2479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 133*2479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 134*2479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 13513Sbill 1362456Swnj /* 1372456Swnj * Routine for configuration to force a dh to interrupt. 1382456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1392456Swnj */ 1402468Swnj /*ARGSUSED*/ 1412395Swnj dhcntrlr(ui, reg) 1422395Swnj struct uba_dinfo *ui; 1432395Swnj caddr_t reg; 1442395Swnj { 1452468Swnj register int br, cvec; /* these are ``value-result'' */ 146*2479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1472421Skre int i; 1482395Swnj 1492456Swnj dhaddr->un.dhcsr = DH_TIE; 1502456Swnj DELAY(5); 1512456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1522421Skre dhaddr->dhbcr = -1; 1532456Swnj dhaddr->dhcar = 0; 1542421Skre dhaddr->dhbar = 1; 1552456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1562421Skre dhaddr->un.dhcsr = 0; 1572456Swnj if (cvec && cvec != 0x200) 1582456Swnj cvec -= 4; /* transmit -> receive */ 1592456Swnj return (1); 1602395Swnj } 1612395Swnj 1622456Swnj /* 1632456Swnj * Routine called to init slave tables. 1642456Swnj */ 1652395Swnj dhslave(ui, reg, slaveno) 1662395Swnj struct uba_dinfo *ui; 1672395Swnj caddr_t reg; 1682395Swnj { 1692395Swnj 1702456Swnj /* no tables to set up */ 1712395Swnj } 1722395Swnj 17313Sbill /* 174*2479Swnj * Configuration routine to cause a dm to interrupt. 175*2479Swnj */ 176*2479Swnj dmcntrlr(um, addr) 177*2479Swnj struct uba_minfo *um; 178*2479Swnj caddr_t addr; 179*2479Swnj { 180*2479Swnj register int br, vec; /* value-result */ 181*2479Swnj register struct dmdevice *dmaddr = (struct dmdevice *)addr; 182*2479Swnj 183*2479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 184*2479Swnj DELAY(20); 185*2479Swnj dmaddr->dmcsr = 0; 186*2479Swnj } 187*2479Swnj 188*2479Swnj dmslave(ui, addr, slave) 189*2479Swnj struct uba_dinfo *ui; 190*2479Swnj caddr_t addr; 191*2479Swnj int slave; 192*2479Swnj { 193*2479Swnj 194*2479Swnj /* no local state to set up */ 195*2479Swnj } 196*2479Swnj 197*2479Swnj /* 1982468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1992468Swnj * is the first dh on this uba. Turn on this dh if this is 2002468Swnj * the first use of it. Also do a dmopen to wait for carrier. 20113Sbill */ 20213Sbill /*ARGSUSED*/ 20313Sbill dhopen(dev, flag) 2042395Swnj dev_t dev; 20513Sbill { 20613Sbill register struct tty *tp; 2072395Swnj register int unit, dh; 208*2479Swnj register struct dhdevice *addr; 2092395Swnj register struct uba_dinfo *ui; 21013Sbill int s; 21113Sbill 2122395Swnj unit = minor(dev); 2132395Swnj dh = unit >> 4; 2142468Swnj if (unit >= NDH11*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 21513Sbill u.u_error = ENXIO; 21613Sbill return; 21713Sbill } 2182395Swnj tp = &dh11[unit]; 2192468Swnj if (tp->t_state&XCLUDE && u.u_uid!=0) { 2202468Swnj u.u_error = EBUSY; 2212468Swnj return; 2222468Swnj } 223*2479Swnj addr = (struct dhdevice *)ui->ui_addr; 22413Sbill tp->t_addr = (caddr_t)addr; 22513Sbill tp->t_oproc = dhstart; 22613Sbill tp->t_iproc = NULL; 22713Sbill tp->t_state |= WOPEN; 2282468Swnj /* 2292468Swnj * While setting up state for this uba and this dh, 2302468Swnj * block uba resets which can clear the state. 2312468Swnj */ 2322468Swnj s = spl5(); 2332421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 234717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2352395Swnj dh_ubinfo[ui->ui_ubanum] = 2362421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2372395Swnj 512+NCLIST*sizeof(struct cblock), 0); 2382456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 23913Sbill } 2402456Swnj if ((dhact&(1<<dh)) == 0) { 2412456Swnj addr->un.dhcsr |= DH_IE; 2422468Swnj DELAY(5); 2432468Swnj dhact |= (1<<dh); 2442456Swnj addr->dhsilo = 16; 2452456Swnj } 24613Sbill splx(s); 2472468Swnj /* 2482468Swnj * If this is first open, initialze tty state to default. 2492468Swnj */ 25013Sbill if ((tp->t_state&ISOPEN) == 0) { 25113Sbill ttychars(tp); 252168Sbill if (tp->t_ispeed == 0) { 2532456Swnj tp->t_ispeed = B300; 2542456Swnj tp->t_ospeed = B300; 255168Sbill tp->t_flags = ODDP|EVENP|ECHO; 256168Sbill } 2572395Swnj dhparam(unit); 25813Sbill } 2592468Swnj /* 2602468Swnj * Wait for carrier, then process line discipline specific open. 2612468Swnj */ 26213Sbill dmopen(dev); 2632395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 26413Sbill } 26513Sbill 26613Sbill /* 2672468Swnj * Close a DH11 line, turning off the DM11. 26813Sbill */ 26913Sbill /*ARGSUSED*/ 27013Sbill dhclose(dev, flag) 2712395Swnj dev_t dev; 2722395Swnj int flag; 27313Sbill { 27413Sbill register struct tty *tp; 2752395Swnj register unit; 27613Sbill 2772395Swnj unit = minor(dev); 2782395Swnj tp = &dh11[unit]; 27913Sbill (*linesw[tp->t_line].l_close)(tp); 280*2479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 28113Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 282*2479Swnj dmctl(unit, DML_OFF, DMSET); 28313Sbill ttyclose(tp); 28413Sbill } 28513Sbill 28613Sbill dhread(dev) 2872395Swnj dev_t dev; 28813Sbill { 2892395Swnj register struct tty *tp; 29013Sbill 2912395Swnj tp = &dh11[minor(dev)]; 29213Sbill (*linesw[tp->t_line].l_read)(tp); 29313Sbill } 29413Sbill 29513Sbill dhwrite(dev) 2962395Swnj dev_t dev; 29713Sbill { 2982395Swnj register struct tty *tp; 29913Sbill 3002395Swnj tp = &dh11[minor(dev)]; 30113Sbill (*linesw[tp->t_line].l_write)(tp); 30213Sbill } 30313Sbill 30413Sbill /* 30513Sbill * DH11 receiver interrupt. 30613Sbill */ 3072395Swnj dhrint(dh) 3082395Swnj int dh; 30913Sbill { 31013Sbill register struct tty *tp; 3112395Swnj register c; 312*2479Swnj register struct dhdevice *addr; 313117Sbill register struct tty *tp0; 3142395Swnj register struct uba_dinfo *ui; 315139Sbill int s; 31613Sbill 3172395Swnj ui = dhinfo[dh]; 318*2479Swnj if (ui == 0 || ui->ui_alive == 0) 319*2479Swnj return; 320*2479Swnj addr = (struct dhdevice *)ui->ui_addr; 3212468Swnj tp0 = &dh11[dh<<4]; 3222468Swnj /* 3232468Swnj * Loop fetching characters from the silo for this 3242468Swnj * dh until there are no more in the silo. 3252468Swnj */ 3262468Swnj while ((c = addr->dhrcr) < 0) { 3272468Swnj tp = tp0 + ((c>>8)&0xf); 3282468Swnj if ((tp->t_state&ISOPEN)==0) { 32913Sbill wakeup((caddr_t)tp); 33013Sbill continue; 33113Sbill } 3322468Swnj if (c & DH_PE) 33313Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 33413Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 33513Sbill continue; 3362468Swnj if (c & DH_DO) 33713Sbill printf("O"); 3382468Swnj if (c & DH_FE) 3392468Swnj /* 3402468Swnj * At framing error (break) generate 3412468Swnj * a null (in raw mode, for getty), or a 3422468Swnj * interrupt (in cooked/cbreak mode). 3432468Swnj */ 34413Sbill if (tp->t_flags&RAW) 3452468Swnj c = 0; 34613Sbill else 347184Sbill c = tun.t_intrc; 348139Sbill if (tp->t_line == NETLDISC) { 349117Sbill c &= 0177; 350168Sbill BKINPUT(c, tp); 351117Sbill } else 3522468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 35313Sbill } 35413Sbill } 35513Sbill 35613Sbill /* 3572468Swnj * Ioctl for DH11. 35813Sbill */ 35913Sbill /*ARGSUSED*/ 36013Sbill dhioctl(dev, cmd, addr, flag) 3612395Swnj caddr_t addr; 36213Sbill { 36313Sbill register struct tty *tp; 3642395Swnj register unit = minor(dev); 36513Sbill 3662395Swnj tp = &dh11[unit]; 367113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 3682468Swnj if (cmd == 0) 369113Sbill return; 3701895Swnj if (ttioctl(tp, cmd, addr, flag)) { 3712468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 3722395Swnj dhparam(unit); 373168Sbill } else switch(cmd) { 374168Sbill case TIOCSBRK: 375*2479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 376168Sbill break; 377168Sbill case TIOCCBRK: 378*2479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 379168Sbill break; 380168Sbill case TIOCSDTR: 381*2479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 382168Sbill break; 383168Sbill case TIOCCDTR: 384*2479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 385168Sbill break; 386168Sbill default: 38713Sbill u.u_error = ENOTTY; 388168Sbill } 38913Sbill } 39013Sbill 39113Sbill /* 39213Sbill * Set parameters from open or stty into the DH hardware 39313Sbill * registers. 39413Sbill */ 3952395Swnj dhparam(unit) 3962395Swnj register int unit; 39713Sbill { 39813Sbill register struct tty *tp; 399*2479Swnj register struct dhdevice *addr; 4002395Swnj register int lpar; 401300Sbill int s; 40213Sbill 4032395Swnj tp = &dh11[unit]; 404*2479Swnj addr = (struct dhdevice *)tp->t_addr; 4052468Swnj /* 4062468Swnj * Block interrupts so parameters will be set 4072468Swnj * before the line interrupts. 4082468Swnj */ 409300Sbill s = spl5(); 4102468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 41113Sbill if ((tp->t_ispeed)==0) { 41213Sbill tp->t_state |= HUPCLS; 413*2479Swnj dmctl(unit, DML_OFF, DMSET); 41413Sbill return; 41513Sbill } 4162395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4172468Swnj if ((tp->t_ispeed) == B134) 4182395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4192312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 4202395Swnj lpar |= BITS8; 42113Sbill else 4222395Swnj lpar |= BITS7|PENABLE; 42313Sbill if ((tp->t_flags&EVENP) == 0) 4242395Swnj lpar |= OPAR; 4252468Swnj if ((tp->t_ospeed) == B110) 4262395Swnj lpar |= TWOSB; 4272395Swnj addr->dhlpr = lpar; 428300Sbill splx(s); 42913Sbill } 43013Sbill 43113Sbill /* 43213Sbill * DH11 transmitter interrupt. 43313Sbill * Restart each line which used to be active but has 43413Sbill * terminated transmission since the last interrupt. 43513Sbill */ 4362395Swnj dhxint(dh) 4372395Swnj int dh; 43813Sbill { 43913Sbill register struct tty *tp; 440*2479Swnj register struct dhdevice *addr; 44113Sbill short ttybit, bar, *sbar; 4422395Swnj register struct uba_dinfo *ui; 4432468Swnj register int unit; 444144Sbill int s; 4452468Swnj u_short cnt; 44613Sbill 4472395Swnj ui = dhinfo[dh]; 448*2479Swnj addr = (struct dhdevice *)ui->ui_addr; 4492456Swnj if (addr->un.dhcsr & DH_NXM) { 4502468Swnj DELAY(5); 4512456Swnj addr->un.dhcsr |= DH_CNI; 4522468Swnj printf("dh%d NXM\n", dh); 453105Sbill } 4542395Swnj sbar = &dhsar[dh]; 45513Sbill bar = *sbar & ~addr->dhbar; 4562395Swnj unit = dh * 16; ttybit = 1; 4572468Swnj addr->un.dhcsr &= (short)~DH_TI; 4582468Swnj for (; bar; unit++, ttybit <<= 1) { 4592468Swnj if (bar & ttybit) { 46013Sbill *sbar &= ~ttybit; 46113Sbill bar &= ~ttybit; 4622395Swnj tp = &dh11[unit]; 463113Sbill tp->t_state &= ~BUSY; 464113Sbill if (tp->t_state&FLUSH) 465113Sbill tp->t_state &= ~FLUSH; 466113Sbill else { 4672456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4682468Swnj DELAY(5); 4692468Swnj /* 4702468Swnj * Do arithmetic in a short to make up 4712468Swnj * for lost 16&17 bits. 4722468Swnj */ 4732468Swnj cnt = addr->dhcar - 4742468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4752468Swnj ndflush(&tp->t_outq, cnt); 476113Sbill } 477113Sbill if (tp->t_line) 47813Sbill (*linesw[tp->t_line].l_start)(tp); 479113Sbill else 48013Sbill dhstart(tp); 48113Sbill } 48213Sbill } 48313Sbill } 48413Sbill 48513Sbill /* 48613Sbill * Start (restart) transmission on the given DH11 line. 48713Sbill */ 48813Sbill dhstart(tp) 4892395Swnj register struct tty *tp; 49013Sbill { 491*2479Swnj register struct dhdevice *addr; 4922468Swnj register int car, dh, unit, nch; 4932395Swnj int s; 49413Sbill 4952468Swnj unit = minor(tp->t_dev); 4962468Swnj dh = unit >> 4; 4972468Swnj unit &= 0xf; 498*2479Swnj addr = (struct dhdevice *)tp->t_addr; 4992468Swnj 50013Sbill /* 5012468Swnj * Must hold interrupts in following code to prevent 5022468Swnj * state of the tp from changing. 50313Sbill */ 50413Sbill s = spl5(); 5052468Swnj /* 5062468Swnj * If it's currently active, or delaying, no need to do anything. 5072468Swnj */ 50813Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 50913Sbill goto out; 5102468Swnj /* 5112468Swnj * If there are sleepers, and output has drained below low 5122468Swnj * water mark, wake up the sleepers. 5132468Swnj */ 5142395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 51513Sbill tp->t_state &= ~ASLEEP; 51613Sbill if (tp->t_chan) 517168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 518168Sbill else 51913Sbill wakeup((caddr_t)&tp->t_outq); 52013Sbill } 5212468Swnj /* 5222468Swnj * Now restart transmission unless the output queue is 5232468Swnj * empty. 5242468Swnj */ 52513Sbill if (tp->t_outq.c_cc == 0) 52613Sbill goto out; 5272395Swnj if (tp->t_flags & RAW) 52813Sbill nch = ndqb(&tp->t_outq, 0); 5292395Swnj else { 53013Sbill nch = ndqb(&tp->t_outq, 0200); 5312468Swnj /* 5322468Swnj * If first thing on queue is a delay process it. 5332468Swnj */ 53413Sbill if (nch == 0) { 53513Sbill nch = getc(&tp->t_outq); 5362468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 53713Sbill tp->t_state |= TIMEOUT; 53813Sbill goto out; 53913Sbill } 54013Sbill } 5412468Swnj /* 5422468Swnj * If characters to transmit, restart transmission. 5432468Swnj */ 54413Sbill if (nch) { 5452468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5462468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5472468Swnj DELAY(5); 5482468Swnj unit = 1 << unit; 5492468Swnj dhsar[dh] |= unit; 5502468Swnj addr->dhcar = car; 55113Sbill addr->dhbcr = -nch; 5522468Swnj addr->dhbar |= unit; 55313Sbill tp->t_state |= BUSY; 55413Sbill } 5552395Swnj out: 55613Sbill splx(s); 55713Sbill } 55813Sbill 55913Sbill /* 5602468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 56113Sbill */ 56213Sbill /*ARGSUSED*/ 56313Sbill dhstop(tp, flag) 5642468Swnj register struct tty *tp; 56513Sbill { 566*2479Swnj register struct dhdevice *addr; 5672395Swnj register int unit, s; 56813Sbill 569*2479Swnj addr = (struct dhdevice *)tp->t_addr; 5702468Swnj /* 5712468Swnj * Block input/output interrupts while messing with state. 5722468Swnj */ 5732468Swnj s = spl5(); 574113Sbill if (tp->t_state & BUSY) { 5752468Swnj /* 5762468Swnj * Device is transmitting; stop output 5772468Swnj * by selecting the line and setting the byte 5782468Swnj * count to -1. We will clean up later 5792468Swnj * by examining the address where the dh stopped. 5802468Swnj */ 5812395Swnj unit = minor(tp->t_dev); 5822456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5832468Swnj DELAY(5); 58413Sbill if ((tp->t_state&TTSTOP)==0) 58513Sbill tp->t_state |= FLUSH; 586113Sbill addr->dhbcr = -1; 587113Sbill } 58813Sbill splx(s); 58913Sbill } 59013Sbill 591168Sbill /* 592280Sbill * Reset state of driver if UBA reset was necessary. 593280Sbill * Reset the csrl and lpr registers on open lines, and 594280Sbill * restart transmitters. 595280Sbill */ 5962395Swnj dhreset(uban) 5972468Swnj int uban; 598280Sbill { 5992395Swnj register int dh, unit; 600280Sbill register struct tty *tp; 6012395Swnj register struct uba_dinfo *ui; 6022421Skre int i; 603280Sbill 6042421Skre if (dh_ubinfo[uban] == 0) 6052421Skre return; 606280Sbill printf(" dh"); 6072421Skre ubarelse(uban, &dh_ubinfo[uban]); 6082421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6092421Skre 512+NCLIST*sizeof (struct cblock), 0); 6102421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6112395Swnj dh = 0; 6122421Skre for (dh = 0; dh < NDH11; dh++) { 6132421Skre ui = dhinfo[dh]; 6142421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6152421Skre continue; 616*2479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6172468Swnj DELAY(5); 618*2479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6192421Skre unit = dh * 16; 6202421Skre for (i = 0; i < 16; i++) { 6212421Skre tp = &dh11[unit]; 6222421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 6232421Skre dhparam(unit); 624*2479Swnj dmctl(unit, DML_ON, DMSET); 6252421Skre tp->t_state &= ~BUSY; 6262421Skre dhstart(tp); 6272421Skre } 6282421Skre unit++; 629300Sbill } 630300Sbill } 631300Sbill dhtimer(); 632280Sbill } 6332395Swnj 6342468Swnj /* 6352468Swnj * At software clock interrupt time or after a UNIBUS reset 6362468Swnj * empty all the dh silos. 6372468Swnj */ 6382456Swnj dhtimer() 6392456Swnj { 6402456Swnj register int dh; 6412456Swnj 6422456Swnj for (dh = 0; dh < NDH11; dh++) 6432456Swnj dhrint(dh); 6442456Swnj } 6452456Swnj 6462468Swnj /* 647*2479Swnj * Turn on the line associated with dh dev. 6482468Swnj */ 6492468Swnj dmopen(dev) 6502468Swnj dev_t dev; 6512468Swnj { 6522468Swnj register struct tty *tp; 6532468Swnj register struct dmdevice *addr; 6542468Swnj register struct uba_dinfo *ui; 6552468Swnj register int unit; 6562468Swnj register int dm; 6572468Swnj 6582468Swnj unit = minor(dev); 659*2479Swnj dm = unit >> 4; 6602468Swnj tp = &dh11[unit]; 6612468Swnj if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 6622468Swnj tp->t_state |= CARR_ON; 6632468Swnj return; 6642468Swnj } 6652468Swnj addr = (struct dmdevice *)ui->ui_addr; 6662468Swnj spl5(); 667*2479Swnj addr->dmcsr &= ~DM_SE; 668*2479Swnj while (addr->dmcsr & DM_BUSY) 6692468Swnj ; 6702468Swnj addr->dmcsr = unit & 0xf; 671*2479Swnj addr->dmlstat = DML_ON; 672*2479Swnj if (addr->dmlstat&DML_CAR) 6732468Swnj tp->t_state |= CARR_ON; 674*2479Swnj addr->dmcsr = DH_IE|DM_SE; 6752468Swnj while ((tp->t_state&CARR_ON)==0) 6762468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 6772468Swnj spl0(); 6782468Swnj } 6792468Swnj 6802468Swnj /* 6812468Swnj * Dump control bits into the DM registers. 6822468Swnj */ 6832468Swnj dmctl(dev, bits, how) 6842468Swnj dev_t dev; 6852468Swnj int bits, how; 6862468Swnj { 6872468Swnj register struct uba_dinfo *ui; 6882468Swnj register struct dmdevice *addr; 6892468Swnj register int unit, s; 6902468Swnj int dm; 6912468Swnj 6922468Swnj unit = minor(dev); 6932468Swnj dm = unit >> 4; 6942468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 6952468Swnj return; 6962468Swnj addr = (struct dmdevice *)ui->ui_addr; 6972468Swnj s = spl5(); 698*2479Swnj addr->dmcsr &= ~DM_SE; 699*2479Swnj while (addr->dmcsr & DM_BUSY) 7002468Swnj ; 7012468Swnj addr->dmcsr = unit & 0xf; 7022468Swnj switch(how) { 7032468Swnj case DMSET: 7042468Swnj addr->dmlstat = bits; 7052468Swnj break; 7062468Swnj case DMBIS: 7072468Swnj addr->dmlstat |= bits; 7082468Swnj break; 7092468Swnj case DMBIC: 7102468Swnj addr->dmlstat &= ~bits; 7112468Swnj break; 7122468Swnj } 713*2479Swnj addr->dmcsr = DH_IE|DM_SE; 7142468Swnj splx(s); 7152468Swnj } 7162468Swnj 7172468Swnj /* 7182468Swnj * DM11 interrupt; deal with carrier transitions. 7192468Swnj */ 7202468Swnj dmintr(dm) 7212468Swnj register int dm; 7222468Swnj { 7232468Swnj register struct uba_dinfo *ui; 7242468Swnj register struct tty *tp; 7252468Swnj register struct dmdevice *addr; 7262468Swnj 7272468Swnj ui = dminfo[dm]; 728*2479Swnj if (ui == 0) 729*2479Swnj return; 7302468Swnj addr = (struct dmdevice *)ui->ui_addr; 731*2479Swnj if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CF) { 7322468Swnj tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7332468Swnj wakeup((caddr_t)&tp->t_rawq); 7342468Swnj if ((tp->t_state&WOPEN)==0 && 7352468Swnj (tp->t_local&LMDMBUF)) { 736*2479Swnj if (addr->dmlstat & DML_CAR) { 7372468Swnj tp->t_state &= ~TTSTOP; 7382468Swnj ttstart(tp); 7392468Swnj } else if ((tp->t_state&TTSTOP) == 0) { 7402468Swnj tp->t_state |= TTSTOP; 7412468Swnj dhstop(tp, 0); 7422468Swnj } 743*2479Swnj } else if ((addr->dmlstat&DML_CAR)==0) { 7442468Swnj if ((tp->t_state&WOPEN)==0 && 7452468Swnj (tp->t_local&LNOHANG)==0) { 7462468Swnj gsignal(tp->t_pgrp, SIGHUP); 7472468Swnj gsignal(tp->t_pgrp, SIGCONT); 7482468Swnj addr->dmlstat = 0; 7492468Swnj flushtty(tp, FREAD|FWRITE); 7502468Swnj } 7512468Swnj tp->t_state &= ~CARR_ON; 7522468Swnj } else 7532468Swnj tp->t_state |= CARR_ON; 754*2479Swnj addr->dmcsr = DH_IE|DM_SE; 7552468Swnj } 7562468Swnj } 757