1*9771Ssam /* dh.c 4.56 82/12/17 */ 213Sbill 31934Swnj #include "dh.h" 42643Swnj #if NDH > 0 513Sbill /* 62479Swnj * DH-11/DM-11 driver 713Sbill */ 8*9771Ssam #include "../machine/pte.h" 9*9771Ssam 102730Swnj #include "bk.h" 1113Sbill #include "../h/param.h" 1213Sbill #include "../h/conf.h" 1313Sbill #include "../h/dir.h" 1413Sbill #include "../h/user.h" 156185Ssam #include "../h/proc.h" 169549Ssam #include "../h/ioctl.h" 1713Sbill #include "../h/tty.h" 1813Sbill #include "../h/map.h" 192395Swnj #include "../h/buf.h" 202566Swnj #include "../h/vm.h" 218472Sroot 228472Sroot #include "../vaxuba/ubareg.h" 238472Sroot #include "../vaxuba/ubavar.h" 248472Sroot 25113Sbill #include "../h/bk.h" 261561Sbill #include "../h/clist.h" 272468Swnj #include "../h/file.h" 287725Sroot #include "../h/uio.h" 2913Sbill 302468Swnj /* 312479Swnj * Definition of the driver for the auto-configuration program. 322479Swnj * There is one definition for the dh and one for the dm. 332468Swnj */ 342605Swnj int dhprobe(), dhattach(), dhrint(), dhxint(); 352974Swnj struct uba_device *dhinfo[NDH]; 362395Swnj u_short dhstd[] = { 0 }; 372395Swnj struct uba_driver dhdriver = 382605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 392395Swnj 402605Swnj int dmprobe(), dmattach(), dmintr(); 412974Swnj struct uba_device *dminfo[NDH]; 422479Swnj u_short dmstd[] = { 0 }; 432479Swnj struct uba_driver dmdriver = 442605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 4513Sbill 462479Swnj struct dhdevice 472479Swnj { 482479Swnj union { 492479Swnj short dhcsr; /* control-status register */ 502479Swnj char dhcsrl; /* low byte for line select */ 512479Swnj } un; 522479Swnj short dhrcr; /* receive character register */ 532479Swnj short dhlpr; /* line parameter register */ 542479Swnj u_short dhcar; /* current address register */ 552479Swnj short dhbcr; /* byte count register */ 562479Swnj u_short dhbar; /* buffer active register */ 572479Swnj short dhbreak; /* break control register */ 582479Swnj short dhsilo; /* silo status register */ 592479Swnj }; 6013Sbill 616615Ssam #ifndef PORTSELECTOR 626615Ssam #define ISPEED B300 636615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 646615Ssam #else 656615Ssam #define ISPEED B4800 666615Ssam #define IFLAGS (EVENP|ODDP) 676615Ssam #endif 686615Ssam 692456Swnj /* Bits in dhcsr */ 702456Swnj #define DH_TI 0100000 /* transmit interrupt */ 712456Swnj #define DH_SI 0040000 /* storage interrupt */ 722456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 732456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 742456Swnj #define DH_MC 0004000 /* master clear */ 752456Swnj #define DH_NXM 0002000 /* non-existant memory */ 762456Swnj #define DH_MM 0001000 /* maintenance mode */ 772456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 782456Swnj #define DH_RI 0000200 /* receiver interrupt */ 792456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 8013Sbill 812479Swnj /* Bits in dhlpr */ 822479Swnj #define BITS6 01 832479Swnj #define BITS7 02 842479Swnj #define BITS8 03 852479Swnj #define TWOSB 04 862479Swnj #define PENABLE 020 872479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */ 882479Swnj #define OPAR 040 892479Swnj #define HDUPLX 040000 902479Swnj 912456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 922456Swnj 932456Swnj /* Bits in dhrcr */ 942479Swnj #define DH_PE 0010000 /* parity error */ 952479Swnj #define DH_FE 0020000 /* framing error */ 962479Swnj #define DH_DO 0040000 /* data overrun */ 972456Swnj 982479Swnj struct dmdevice 992479Swnj { 1002479Swnj short dmcsr; /* control status register */ 1012479Swnj short dmlstat; /* line status register */ 1022479Swnj short dmpad1[2]; 1032479Swnj }; 1042479Swnj 1052479Swnj /* bits in dm csr */ 1062479Swnj #define DM_RF 0100000 /* ring flag */ 1072479Swnj #define DM_CF 0040000 /* carrier flag */ 1082479Swnj #define DM_CTS 0020000 /* clear to send */ 1092479Swnj #define DM_SRF 0010000 /* secondary receive flag */ 1102479Swnj #define DM_CS 0004000 /* clear scan */ 1112479Swnj #define DM_CM 0002000 /* clear multiplexor */ 1122479Swnj #define DM_MM 0001000 /* maintenance mode */ 1132479Swnj #define DM_STP 0000400 /* step */ 1142479Swnj #define DM_DONE 0000200 /* scanner is done */ 1152479Swnj #define DM_IE 0000100 /* interrupt enable */ 1162479Swnj #define DM_SE 0000040 /* scan enable */ 1172479Swnj #define DM_BUSY 0000020 /* scan busy */ 1182479Swnj 1192479Swnj /* bits in dm lsr */ 1202479Swnj #define DML_RNG 0000200 /* ring */ 1212479Swnj #define DML_CAR 0000100 /* carrier detect */ 1222479Swnj #define DML_CTS 0000040 /* clear to send */ 1232479Swnj #define DML_SR 0000020 /* secondary receive */ 1242479Swnj #define DML_ST 0000010 /* secondary transmit */ 1252479Swnj #define DML_RTS 0000004 /* request to send */ 1262479Swnj #define DML_DTR 0000002 /* data terminal ready */ 1272479Swnj #define DML_LE 0000001 /* line enable */ 1282479Swnj 1293792Swnj #define DML_ON (DML_DTR|DML_RTS|DML_LE) 1302479Swnj #define DML_OFF (DML_LE) 1312479Swnj 13213Sbill /* 1332479Swnj * Local variables for the driver 13413Sbill */ 1352643Swnj short dhsar[NDH]; /* software copy of last bar */ 1362643Swnj short dhsoftCAR[NDH]; 13713Sbill 1382643Swnj struct tty dh11[NDH*16]; 1392643Swnj int ndh11 = NDH*16; 1402479Swnj int dhact; /* mask of active dh's */ 1412479Swnj int dhstart(), ttrstrt(); 14213Sbill 1432479Swnj /* 1442479Swnj * The clist space is mapped by the driver onto each UNIBUS. 1452479Swnj * The UBACVT macro converts a clist space address for unibus uban 1462479Swnj * into an i/o space address for the DMA routine. 1472479Swnj */ 1482479Swnj int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1492479Swnj int cbase[MAXNUBA]; /* base address in unibus map */ 1502479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 15113Sbill 1522456Swnj /* 1532456Swnj * Routine for configuration to force a dh to interrupt. 1542456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1552456Swnj */ 1562468Swnj /*ARGSUSED*/ 1572605Swnj dhprobe(reg) 1582395Swnj caddr_t reg; 1592395Swnj { 1602468Swnj register int br, cvec; /* these are ``value-result'' */ 1612479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1622395Swnj 1632605Swnj #ifdef lint 1642605Swnj br = 0; cvec = br; br = cvec; 1657384Sroot if (ndh11 == 0) ndh11 = 1; 1664932Swnj dhrint(0); dhxint(0); 1672605Swnj #endif 1682696Swnj #ifndef notdef 1692566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1706380Swnj DELAY(1000); 1717384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1722566Swnj dhaddr->un.dhcsr = 0; 1732566Swnj #else 1742456Swnj dhaddr->un.dhcsr = DH_TIE; 1752456Swnj DELAY(5); 1762456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1772421Skre dhaddr->dhbcr = -1; 1782456Swnj dhaddr->dhcar = 0; 1792421Skre dhaddr->dhbar = 1; 1802456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1812421Skre dhaddr->un.dhcsr = 0; 1822456Swnj if (cvec && cvec != 0x200) 1832456Swnj cvec -= 4; /* transmit -> receive */ 1842482Swnj #endif 1857408Skre return (sizeof (struct dhdevice)); 1862395Swnj } 1872395Swnj 1882456Swnj /* 1892605Swnj * Routine called to attach a dh. 1902456Swnj */ 1912605Swnj dhattach(ui) 1922974Swnj struct uba_device *ui; 1932395Swnj { 1942395Swnj 1952566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1962395Swnj } 1972395Swnj 19813Sbill /* 1992479Swnj * Configuration routine to cause a dm to interrupt. 2002479Swnj */ 2012605Swnj dmprobe(reg) 2022605Swnj caddr_t reg; 2032479Swnj { 2042479Swnj register int br, vec; /* value-result */ 2052605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 2062479Swnj 2072605Swnj #ifdef lint 2083101Swnj br = 0; vec = br; br = vec; 2096185Ssam dmintr(0); 2102605Swnj #endif 2112479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 2122479Swnj DELAY(20); 2132479Swnj dmaddr->dmcsr = 0; 2142605Swnj return (1); 2152479Swnj } 2162479Swnj 2172605Swnj /*ARGSUSED*/ 2182605Swnj dmattach(ui) 2192974Swnj struct uba_device *ui; 2202479Swnj { 2212479Swnj 2222479Swnj /* no local state to set up */ 2232479Swnj } 2242479Swnj 2252479Swnj /* 2262468Swnj * Open a DH11 line, mapping the clist onto the uba if this 2272468Swnj * is the first dh on this uba. Turn on this dh if this is 2282468Swnj * the first use of it. Also do a dmopen to wait for carrier. 22913Sbill */ 23013Sbill /*ARGSUSED*/ 23113Sbill dhopen(dev, flag) 2322395Swnj dev_t dev; 23313Sbill { 23413Sbill register struct tty *tp; 2352395Swnj register int unit, dh; 2362479Swnj register struct dhdevice *addr; 2372974Swnj register struct uba_device *ui; 23813Sbill int s; 23913Sbill 2402395Swnj unit = minor(dev); 2412395Swnj dh = unit >> 4; 2428566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 2438566Sroot return (ENXIO); 2442395Swnj tp = &dh11[unit]; 2458566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2468566Sroot return (EBUSY); 2472479Swnj addr = (struct dhdevice *)ui->ui_addr; 24813Sbill tp->t_addr = (caddr_t)addr; 24913Sbill tp->t_oproc = dhstart; 2505406Swnj tp->t_state |= TS_WOPEN; 2512468Swnj /* 2522468Swnj * While setting up state for this uba and this dh, 2532468Swnj * block uba resets which can clear the state. 2542468Swnj */ 2552468Swnj s = spl5(); 2562421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 257717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 2582395Swnj dh_ubinfo[ui->ui_ubanum] = 2592421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2602770Swnj 512+nclist*sizeof(struct cblock), 0); 2612456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 26213Sbill } 2632456Swnj if ((dhact&(1<<dh)) == 0) { 2642456Swnj addr->un.dhcsr |= DH_IE; 2652468Swnj dhact |= (1<<dh); 2662456Swnj addr->dhsilo = 16; 2672456Swnj } 26813Sbill splx(s); 2692468Swnj /* 2702468Swnj * If this is first open, initialze tty state to default. 2712468Swnj */ 2725406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 27313Sbill ttychars(tp); 2746615Ssam #ifndef PORTSELECTOR 275168Sbill if (tp->t_ispeed == 0) { 2766615Ssam #endif 2776615Ssam tp->t_ispeed = ISPEED; 2786615Ssam tp->t_ospeed = ISPEED; 2796615Ssam tp->t_flags = IFLAGS; 2806615Ssam #ifndef PORTSELECTOR 281168Sbill } 2826615Ssam #endif 2832395Swnj dhparam(unit); 28413Sbill } 2852468Swnj /* 2862468Swnj * Wait for carrier, then process line discipline specific open. 2872468Swnj */ 28813Sbill dmopen(dev); 2898566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 29013Sbill } 29113Sbill 29213Sbill /* 2932468Swnj * Close a DH11 line, turning off the DM11. 29413Sbill */ 29513Sbill /*ARGSUSED*/ 29613Sbill dhclose(dev, flag) 2972395Swnj dev_t dev; 2982395Swnj int flag; 29913Sbill { 30013Sbill register struct tty *tp; 3012395Swnj register unit; 30213Sbill 3032395Swnj unit = minor(dev); 3042395Swnj tp = &dh11[unit]; 30513Sbill (*linesw[tp->t_line].l_close)(tp); 3062479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 3075406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3082479Swnj dmctl(unit, DML_OFF, DMSET); 30913Sbill ttyclose(tp); 31013Sbill } 31113Sbill 3127725Sroot dhread(dev, uio) 3132395Swnj dev_t dev; 3147725Sroot struct uio *uio; 31513Sbill { 3168490Sroot register struct tty *tp = &dh11[minor(dev)]; 31713Sbill 3187725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 31913Sbill } 32013Sbill 3217831Sroot dhwrite(dev, uio) 3222395Swnj dev_t dev; 3237831Sroot struct uio *uio; 32413Sbill { 3258490Sroot register struct tty *tp = &dh11[minor(dev)]; 32613Sbill 3278490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 32813Sbill } 32913Sbill 33013Sbill /* 33113Sbill * DH11 receiver interrupt. 33213Sbill */ 3332395Swnj dhrint(dh) 3342395Swnj int dh; 33513Sbill { 33613Sbill register struct tty *tp; 3372395Swnj register c; 3382479Swnj register struct dhdevice *addr; 339117Sbill register struct tty *tp0; 3402974Swnj register struct uba_device *ui; 3412924Swnj int overrun = 0; 34213Sbill 3432395Swnj ui = dhinfo[dh]; 3442479Swnj if (ui == 0 || ui->ui_alive == 0) 3452479Swnj return; 3462479Swnj addr = (struct dhdevice *)ui->ui_addr; 3472468Swnj tp0 = &dh11[dh<<4]; 3482468Swnj /* 3492468Swnj * Loop fetching characters from the silo for this 3502468Swnj * dh until there are no more in the silo. 3512468Swnj */ 3522468Swnj while ((c = addr->dhrcr) < 0) { 3532468Swnj tp = tp0 + ((c>>8)&0xf); 3546615Ssam #ifndef PORTSELECTOR 3555406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 3566615Ssam #else 3576615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 3586615Ssam #endif 35913Sbill wakeup((caddr_t)tp); 36013Sbill continue; 36113Sbill } 3622468Swnj if (c & DH_PE) 36313Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 36413Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 36513Sbill continue; 3662924Swnj if ((c & DH_DO) && overrun == 0) { 3672924Swnj printf("dh%d: silo overflow\n", dh); 3682924Swnj overrun = 1; 3692924Swnj } 3702468Swnj if (c & DH_FE) 3712468Swnj /* 3722468Swnj * At framing error (break) generate 3732468Swnj * a null (in raw mode, for getty), or a 3742468Swnj * interrupt (in cooked/cbreak mode). 3752468Swnj */ 37613Sbill if (tp->t_flags&RAW) 3772468Swnj c = 0; 37813Sbill else 3799549Ssam c = tp->t_intrc; 3802730Swnj #if NBK > 0 381139Sbill if (tp->t_line == NETLDISC) { 382117Sbill c &= 0177; 383168Sbill BKINPUT(c, tp); 384117Sbill } else 3852730Swnj #endif 3862468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 38713Sbill } 38813Sbill } 38913Sbill 39013Sbill /* 3912468Swnj * Ioctl for DH11. 39213Sbill */ 39313Sbill /*ARGSUSED*/ 3947629Ssam dhioctl(dev, cmd, data, flag) 3957629Ssam caddr_t data; 39613Sbill { 39713Sbill register struct tty *tp; 3988566Sroot register int unit = minor(dev); 3998566Sroot int error; 40013Sbill 4012395Swnj tp = &dh11[unit]; 4028566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 4038566Sroot if (error >= 0) 4048566Sroot return (error); 4058566Sroot error = ttioctl(tp, cmd, data, flag); 4068566Sroot if (error >= 0) { 4077629Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 4082395Swnj dhparam(unit); 4098566Sroot return (error); 4108566Sroot } 4118566Sroot switch (cmd) { 4127629Ssam 413168Sbill case TIOCSBRK: 4142479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 415168Sbill break; 4167629Ssam 417168Sbill case TIOCCBRK: 4182479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 419168Sbill break; 4207629Ssam 421168Sbill case TIOCSDTR: 4222479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 423168Sbill break; 4247629Ssam 425168Sbill case TIOCCDTR: 4262479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 427168Sbill break; 4287629Ssam 429168Sbill default: 4308566Sroot return (ENOTTY); 431168Sbill } 4328566Sroot return (0); 43313Sbill } 43413Sbill 43513Sbill /* 43613Sbill * Set parameters from open or stty into the DH hardware 43713Sbill * registers. 43813Sbill */ 4392395Swnj dhparam(unit) 4402395Swnj register int unit; 44113Sbill { 44213Sbill register struct tty *tp; 4432479Swnj register struct dhdevice *addr; 4442395Swnj register int lpar; 445300Sbill int s; 44613Sbill 4472395Swnj tp = &dh11[unit]; 4482479Swnj addr = (struct dhdevice *)tp->t_addr; 4492468Swnj /* 4502468Swnj * Block interrupts so parameters will be set 4512468Swnj * before the line interrupts. 4522468Swnj */ 453300Sbill s = spl5(); 4542468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 45513Sbill if ((tp->t_ispeed)==0) { 4565406Swnj tp->t_state |= TS_HUPCLS; 4572479Swnj dmctl(unit, DML_OFF, DMSET); 45813Sbill return; 45913Sbill } 4602395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4612468Swnj if ((tp->t_ispeed) == B134) 4622395Swnj lpar |= BITS6|PENABLE|HDUPLX; 4639549Ssam else if (tp->t_flags & (RAW|LITOUT)) 4642395Swnj lpar |= BITS8; 46513Sbill else 4662395Swnj lpar |= BITS7|PENABLE; 46713Sbill if ((tp->t_flags&EVENP) == 0) 4682395Swnj lpar |= OPAR; 4692468Swnj if ((tp->t_ospeed) == B110) 4702395Swnj lpar |= TWOSB; 4712395Swnj addr->dhlpr = lpar; 472300Sbill splx(s); 47313Sbill } 47413Sbill 47513Sbill /* 47613Sbill * DH11 transmitter interrupt. 47713Sbill * Restart each line which used to be active but has 47813Sbill * terminated transmission since the last interrupt. 47913Sbill */ 4802395Swnj dhxint(dh) 4812395Swnj int dh; 48213Sbill { 48313Sbill register struct tty *tp; 4842479Swnj register struct dhdevice *addr; 48513Sbill short ttybit, bar, *sbar; 4862974Swnj register struct uba_device *ui; 4872468Swnj register int unit; 4882605Swnj u_short cntr; 48913Sbill 4902395Swnj ui = dhinfo[dh]; 4912479Swnj addr = (struct dhdevice *)ui->ui_addr; 4922456Swnj if (addr->un.dhcsr & DH_NXM) { 4932456Swnj addr->un.dhcsr |= DH_CNI; 4942924Swnj printf("dh%d: NXM\n", dh); 495105Sbill } 4962395Swnj sbar = &dhsar[dh]; 49713Sbill bar = *sbar & ~addr->dhbar; 4982395Swnj unit = dh * 16; ttybit = 1; 4992468Swnj addr->un.dhcsr &= (short)~DH_TI; 5002468Swnj for (; bar; unit++, ttybit <<= 1) { 5012468Swnj if (bar & ttybit) { 50213Sbill *sbar &= ~ttybit; 50313Sbill bar &= ~ttybit; 5042395Swnj tp = &dh11[unit]; 5055406Swnj tp->t_state &= ~TS_BUSY; 5065406Swnj if (tp->t_state&TS_FLUSH) 5075406Swnj tp->t_state &= ~TS_FLUSH; 508113Sbill else { 5092456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 5102468Swnj /* 5112468Swnj * Do arithmetic in a short to make up 5122468Swnj * for lost 16&17 bits. 5132468Swnj */ 5142605Swnj cntr = addr->dhcar - 5152468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 5163101Swnj ndflush(&tp->t_outq, (int)cntr); 517113Sbill } 518113Sbill if (tp->t_line) 51913Sbill (*linesw[tp->t_line].l_start)(tp); 520113Sbill else 52113Sbill dhstart(tp); 52213Sbill } 52313Sbill } 52413Sbill } 52513Sbill 52613Sbill /* 52713Sbill * Start (restart) transmission on the given DH11 line. 52813Sbill */ 52913Sbill dhstart(tp) 5302395Swnj register struct tty *tp; 53113Sbill { 5322479Swnj register struct dhdevice *addr; 5332468Swnj register int car, dh, unit, nch; 5342395Swnj int s; 53513Sbill 5362468Swnj unit = minor(tp->t_dev); 5372468Swnj dh = unit >> 4; 5382468Swnj unit &= 0xf; 5392479Swnj addr = (struct dhdevice *)tp->t_addr; 5402468Swnj 54113Sbill /* 5422468Swnj * Must hold interrupts in following code to prevent 5432468Swnj * state of the tp from changing. 54413Sbill */ 54513Sbill s = spl5(); 5462468Swnj /* 5472468Swnj * If it's currently active, or delaying, no need to do anything. 5482468Swnj */ 5495406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 55013Sbill goto out; 5512468Swnj /* 5522468Swnj * If there are sleepers, and output has drained below low 5532468Swnj * water mark, wake up the sleepers. 5542468Swnj */ 5555406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5565406Swnj if (tp->t_state&TS_ASLEEP) { 5575406Swnj tp->t_state &= ~TS_ASLEEP; 5585406Swnj wakeup((caddr_t)&tp->t_outq); 5595406Swnj } 5605406Swnj if (tp->t_wsel) { 5615406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5625406Swnj tp->t_wsel = 0; 5635406Swnj tp->t_state &= ~TS_WCOLL; 5645406Swnj } 56513Sbill } 5662468Swnj /* 5672468Swnj * Now restart transmission unless the output queue is 5682468Swnj * empty. 5692468Swnj */ 57013Sbill if (tp->t_outq.c_cc == 0) 57113Sbill goto out; 5729549Ssam if (tp->t_flags & (RAW|LITOUT)) 57313Sbill nch = ndqb(&tp->t_outq, 0); 5742395Swnj else { 57513Sbill nch = ndqb(&tp->t_outq, 0200); 5762468Swnj /* 5772468Swnj * If first thing on queue is a delay process it. 5782468Swnj */ 57913Sbill if (nch == 0) { 58013Sbill nch = getc(&tp->t_outq); 5812468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5825406Swnj tp->t_state |= TS_TIMEOUT; 58313Sbill goto out; 58413Sbill } 58513Sbill } 5862468Swnj /* 5872468Swnj * If characters to transmit, restart transmission. 5882468Swnj */ 58913Sbill if (nch) { 5902468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5912468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5923586Sroot /* 5933586Sroot * The following nonsense with short word 5943586Sroot * is to make sure the dhbar |= word below 5953586Sroot * is done with an interlocking bisw2 instruction. 5963586Sroot */ 5973586Sroot { short word = 1 << unit; 5983586Sroot dhsar[dh] |= word; 5992468Swnj addr->dhcar = car; 60013Sbill addr->dhbcr = -nch; 6013586Sroot addr->dhbar |= word; 6023586Sroot } 6035406Swnj tp->t_state |= TS_BUSY; 60413Sbill } 6052395Swnj out: 60613Sbill splx(s); 60713Sbill } 60813Sbill 60913Sbill /* 6102468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 61113Sbill */ 61213Sbill /*ARGSUSED*/ 61313Sbill dhstop(tp, flag) 6142468Swnj register struct tty *tp; 61513Sbill { 6162479Swnj register struct dhdevice *addr; 6172395Swnj register int unit, s; 61813Sbill 6192479Swnj addr = (struct dhdevice *)tp->t_addr; 6202468Swnj /* 6212468Swnj * Block input/output interrupts while messing with state. 6222468Swnj */ 6232468Swnj s = spl5(); 6245406Swnj if (tp->t_state & TS_BUSY) { 6252468Swnj /* 6262468Swnj * Device is transmitting; stop output 6272468Swnj * by selecting the line and setting the byte 6282468Swnj * count to -1. We will clean up later 6292468Swnj * by examining the address where the dh stopped. 6302468Swnj */ 6312395Swnj unit = minor(tp->t_dev); 6322456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6335406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6345406Swnj tp->t_state |= TS_FLUSH; 635113Sbill addr->dhbcr = -1; 636113Sbill } 63713Sbill splx(s); 63813Sbill } 63913Sbill 640168Sbill /* 641280Sbill * Reset state of driver if UBA reset was necessary. 642280Sbill * Reset the csrl and lpr registers on open lines, and 643280Sbill * restart transmitters. 644280Sbill */ 6452395Swnj dhreset(uban) 6462468Swnj int uban; 647280Sbill { 6482395Swnj register int dh, unit; 649280Sbill register struct tty *tp; 6502974Swnj register struct uba_device *ui; 6512421Skre int i; 652280Sbill 6532421Skre if (dh_ubinfo[uban] == 0) 6542421Skre return; 6552421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6562770Swnj 512+nclist*sizeof (struct cblock), 0); 6572421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6582395Swnj dh = 0; 6592643Swnj for (dh = 0; dh < NDH; dh++) { 6602421Skre ui = dhinfo[dh]; 6612421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6622421Skre continue; 6632924Swnj printf(" dh%d", dh); 6642479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 6652479Swnj ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; 6662421Skre unit = dh * 16; 6672421Skre for (i = 0; i < 16; i++) { 6682421Skre tp = &dh11[unit]; 6695406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6702421Skre dhparam(unit); 6712479Swnj dmctl(unit, DML_ON, DMSET); 6725406Swnj tp->t_state &= ~TS_BUSY; 6732421Skre dhstart(tp); 6742421Skre } 6752421Skre unit++; 676300Sbill } 677300Sbill } 678300Sbill dhtimer(); 679280Sbill } 6802395Swnj 6812468Swnj /* 6822468Swnj * At software clock interrupt time or after a UNIBUS reset 6832468Swnj * empty all the dh silos. 6842468Swnj */ 6852456Swnj dhtimer() 6862456Swnj { 6872456Swnj register int dh; 6888159Sroot register int s = spl5(); 6892456Swnj 6902643Swnj for (dh = 0; dh < NDH; dh++) 6912456Swnj dhrint(dh); 6928159Sroot splx(s); 6932456Swnj } 6942456Swnj 6952468Swnj /* 6962479Swnj * Turn on the line associated with dh dev. 6972468Swnj */ 6982468Swnj dmopen(dev) 6992468Swnj dev_t dev; 7002468Swnj { 7012468Swnj register struct tty *tp; 7022468Swnj register struct dmdevice *addr; 7032974Swnj register struct uba_device *ui; 7042468Swnj register int unit; 7052468Swnj register int dm; 7063792Swnj int s; 7072468Swnj 7082468Swnj unit = minor(dev); 7092479Swnj dm = unit >> 4; 7102468Swnj tp = &dh11[unit]; 7112566Swnj unit &= 0xf; 7122643Swnj if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || 7132566Swnj (dhsoftCAR[dm]&(1<<unit))) { 7145406Swnj tp->t_state |= TS_CARR_ON; 7152468Swnj return; 7162468Swnj } 7172468Swnj addr = (struct dmdevice *)ui->ui_addr; 7183792Swnj s = spl5(); 7192479Swnj addr->dmcsr &= ~DM_SE; 7202479Swnj while (addr->dmcsr & DM_BUSY) 7212468Swnj ; 7222566Swnj addr->dmcsr = unit; 7232479Swnj addr->dmlstat = DML_ON; 7242479Swnj if (addr->dmlstat&DML_CAR) 7255406Swnj tp->t_state |= TS_CARR_ON; 7263792Swnj addr->dmcsr = DM_IE|DM_SE; 7275406Swnj while ((tp->t_state&TS_CARR_ON)==0) 7282468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7293792Swnj splx(s); 7302468Swnj } 7312468Swnj 7322468Swnj /* 7332468Swnj * Dump control bits into the DM registers. 7342468Swnj */ 7352468Swnj dmctl(dev, bits, how) 7362468Swnj dev_t dev; 7372468Swnj int bits, how; 7382468Swnj { 7392974Swnj register struct uba_device *ui; 7402468Swnj register struct dmdevice *addr; 7412468Swnj register int unit, s; 7422468Swnj int dm; 7432468Swnj 7442468Swnj unit = minor(dev); 7452468Swnj dm = unit >> 4; 7462468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7472468Swnj return; 7482468Swnj addr = (struct dmdevice *)ui->ui_addr; 7492468Swnj s = spl5(); 7502479Swnj addr->dmcsr &= ~DM_SE; 7512479Swnj while (addr->dmcsr & DM_BUSY) 7522468Swnj ; 7532468Swnj addr->dmcsr = unit & 0xf; 7542468Swnj switch(how) { 7552468Swnj case DMSET: 7562468Swnj addr->dmlstat = bits; 7572468Swnj break; 7582468Swnj case DMBIS: 7592468Swnj addr->dmlstat |= bits; 7602468Swnj break; 7612468Swnj case DMBIC: 7622468Swnj addr->dmlstat &= ~bits; 7632468Swnj break; 7642468Swnj } 7653792Swnj addr->dmcsr = DM_IE|DM_SE; 7662468Swnj splx(s); 7672468Swnj } 7682468Swnj 7692468Swnj /* 7702468Swnj * DM11 interrupt; deal with carrier transitions. 7712468Swnj */ 7722468Swnj dmintr(dm) 7732468Swnj register int dm; 7742468Swnj { 7752974Swnj register struct uba_device *ui; 7762468Swnj register struct tty *tp; 7772468Swnj register struct dmdevice *addr; 7782468Swnj 7792468Swnj ui = dminfo[dm]; 7802479Swnj if (ui == 0) 7812479Swnj return; 7822468Swnj addr = (struct dmdevice *)ui->ui_addr; 7833997Sroot if (addr->dmcsr&DM_DONE) { 7843997Sroot if (addr->dmcsr&DM_CF) { 7853997Sroot tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 7863997Sroot wakeup((caddr_t)&tp->t_rawq); 7879549Ssam if ((tp->t_state&TS_WOPEN) == 0 && 7889605Ssam (tp->t_flags & MDMBUF)) { 7893997Sroot if (addr->dmlstat & DML_CAR) { 7905406Swnj tp->t_state &= ~TS_TTSTOP; 7913997Sroot ttstart(tp); 7925406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7935406Swnj tp->t_state |= TS_TTSTOP; 7943997Sroot dhstop(tp, 0); 7953997Sroot } 7963997Sroot } else if ((addr->dmlstat&DML_CAR)==0) { 7975406Swnj if ((tp->t_state&TS_WOPEN)==0 && 7989605Ssam (tp->t_flags & NOHANG) == 0) { 7993997Sroot gsignal(tp->t_pgrp, SIGHUP); 8003997Sroot gsignal(tp->t_pgrp, SIGCONT); 8013997Sroot addr->dmlstat = 0; 8023997Sroot flushtty(tp, FREAD|FWRITE); 8033997Sroot } 8045406Swnj tp->t_state &= ~TS_CARR_ON; 8053997Sroot } else 8065406Swnj tp->t_state |= TS_CARR_ON; 8073997Sroot } 8083997Sroot addr->dmcsr = DM_IE|DM_SE; 8092468Swnj } 8102468Swnj } 8112625Swnj #endif 812