1*9772Ssam /* dmf.c 4.16 82/12/17 */ 26940Ssam 36940Ssam #include "dmf.h" 46940Ssam #if NDMF > 0 56940Ssam /* 66940Ssam * DMF32 driver 76940Ssam * 86940Ssam * TODO: 96940Ssam * test with modem 106940Ssam * load as much as possible into silo 116940Ssam * get correct numbers for receive silo parameter timeout 126940Ssam * use auto XON/XOFF 136940Ssam * test reset code 146940Ssam * test with more than one unit 156940Ssam * optimize for efficient DMA and dynamically 166940Ssam * decide between silo and DMA mode 176940Ssam */ 18*9772Ssam #include "../machine/pte.h" 19*9772Ssam 206940Ssam #include "bk.h" 216940Ssam #include "../h/param.h" 226940Ssam #include "../h/conf.h" 236940Ssam #include "../h/dir.h" 246940Ssam #include "../h/user.h" 259550Ssam #include "../h/ioctl.h" 266940Ssam #include "../h/tty.h" 276940Ssam #include "../h/map.h" 286940Ssam #include "../h/buf.h" 296940Ssam #include "../h/vm.h" 306940Ssam #include "../h/bk.h" 316940Ssam #include "../h/clist.h" 326940Ssam #include "../h/file.h" 337726Sroot #include "../h/uio.h" 346940Ssam 358473Sroot #include "../vaxuba/ubareg.h" 368473Sroot #include "../vaxuba/ubavar.h" 378473Sroot 386940Ssam /* 396940Ssam * Definition of the driver for the auto-configuration program. 406940Ssam */ 416940Ssam int dmfprobe(), dmfattach(), dmfrint(), dmfxint(); 426940Ssam struct uba_device *dmfinfo[NDMF]; 436940Ssam u_short dmfstd[] = { 0 }; 446940Ssam struct uba_driver dmfdriver = 456940Ssam { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo }; 466940Ssam 476940Ssam /* 486940Ssam * In this driver, "dmf" (unqualified) refers to the async portion 496940Ssam * of the dmf32, "dmfc" to the combo portion, "dmfs" to the sync 506940Ssam * portion, "dmfl" to the lp portion, and "dmfd" to the dr portion. 516940Ssam */ 526940Ssam struct dmfdevice 536940Ssam { 546940Ssam short dmfccsr0; /* combo csr 0 */ 556940Ssam short dmfccsr1; /* combo csr 1 */ 566940Ssam short dmfs[4]; 576940Ssam short dmfcsr; /* control-status register */ 586940Ssam short dmflpr; /* line parameter register */ 596940Ssam short dmfrbuf; /* receiver buffer (ro) */ 606940Ssam union { 616940Ssam u_short dmfirw; /* indirect register word */ 626940Ssam u_char dmfirc[2]; /* " " bytes */ 636940Ssam } dmfun; 646940Ssam short dmfl[2]; 656940Ssam short dmfd[4]; 666940Ssam }; 676940Ssam 686940Ssam #define dmfrsp dmfrbuf /* receive silo parameter register (wo) */ 696940Ssam #define dmftbuf dmfun.dmfirc[0] /* transmit buffer */ 706940Ssam #define dmftsc dmfun.dmfirc[0] /* transmit silo count */ 716940Ssam #define dmfrms dmfun.dmfirc[1] /* receive modem status */ 726940Ssam #define dmflcr dmfun.dmfirc[0] /* line control register */ 736940Ssam #define dmftms dmfun.dmfirc[1] /* transmit modem status */ 746940Ssam #define dmftba dmfun.dmfirw /* transmit buffer address */ 756940Ssam #define dmftcc dmfun.dmfirw /* transmit character count */ 766940Ssam 776940Ssam /* bits in dmfcsr */ 786940Ssam #define DMF_TI 0100000 /* transmit interrupt */ 796940Ssam #define DMF_TIE 0040000 /* transmit interrupt enable */ 806940Ssam #define DMF_NXM 0020000 /* non-existant memory */ 816940Ssam #define DMF_LIN 0003400 /* transmit line number */ 826940Ssam #define DMF_RI 0000200 /* receiver interrupt */ 836940Ssam #define DMF_RIE 0000100 /* receiver interrupt enable */ 846940Ssam #define DMF_CLR 0000040 /* master reset */ 856940Ssam #define DMF_IAD 0000037 /* indirect address register */ 866940Ssam 876940Ssam #define DMFIR_TBUF 000 /* select tbuf indirect register */ 886940Ssam #define DMFIR_LCR 010 /* select lcr indirect register */ 896940Ssam #define DMFIR_TBA 020 /* select tba indirect register */ 906940Ssam #define DMFIR_TCC 030 /* select tcc indirect register */ 916940Ssam 926940Ssam /* bits in dmflpr */ 936940Ssam #define BITS6 (01<<3) 946940Ssam #define BITS7 (02<<3) 956940Ssam #define BITS8 (03<<3) 966940Ssam #define TWOSB 0200 976940Ssam #define PENABLE 040 986940Ssam /* DEC manuals incorrectly say this bit causes generation of even parity. */ 996940Ssam #define OPAR 0100 1006940Ssam 1016940Ssam #define DMF_IE (DMF_TIE|DMF_RIE) 1026940Ssam 1036940Ssam #define DMF_SILOCNT 32 /* size of DMF output silo (per line) */ 1046940Ssam 1056940Ssam /* bits in dmfrbuf */ 1066940Ssam #define DMF_DSC 0004000 /* data set change */ 1076940Ssam #define DMF_PE 0010000 /* parity error */ 1086940Ssam #define DMF_FE 0020000 /* framing error */ 1096940Ssam #define DMF_DO 0040000 /* data overrun */ 1106940Ssam 1116940Ssam /* bits in dmfrms */ 1126940Ssam #define DMF_USRR 0004 /* user modem signal (pin 25) */ 1136940Ssam #define DMF_SR 0010 /* secondary receive */ 1146940Ssam #define DMF_CTS 0020 /* clear to send */ 1156940Ssam #define DMF_CAR 0040 /* carrier detect */ 1166940Ssam #define DMF_RNG 0100 /* ring */ 1176940Ssam #define DMF_DSR 0200 /* data set ready */ 1186940Ssam 1196940Ssam /* bits in dmftms */ 1206940Ssam #define DMF_USRW 0001 /* user modem signal (pin 18) */ 1216940Ssam #define DMF_DTR 0002 /* data terminal ready */ 1226940Ssam #define DMF_RATE 0004 /* data signal rate select */ 1236940Ssam #define DMF_ST 0010 /* secondary transmit */ 1246940Ssam #define DMF_RTS 0020 /* request to send */ 1256940Ssam #define DMF_BRK 0040 /* pseudo break bit */ 1266940Ssam #define DMF_PREEMPT 0200 /* preempt output */ 1276940Ssam 1286940Ssam /* flags for modem control */ 1296940Ssam #define DMF_ON (DMF_DTR|DMF_RTS) 1306940Ssam #define DMF_OFF 0 1316940Ssam 1326940Ssam /* bits in dmflcr */ 1336940Ssam #define DMF_MIE 0040 /* modem interrupt enable */ 1346940Ssam #define DMF_FLUSH 0020 /* flush transmit silo */ 1356940Ssam #define DMF_RBRK 0010 /* real break bit */ 1366940Ssam #define DMF_RE 0004 /* receive enable */ 1376940Ssam #define DMF_AUTOX 0002 /* auto XON/XOFF */ 1386940Ssam #define DMF_TE 0001 /* transmit enable */ 1396940Ssam 1406940Ssam #define DMFLCR_ENA (DMF_MIE|DMF_RE|DMF_TE) 1416940Ssam 1426940Ssam /* bits in dm lsr, copied from dh.c */ 1436940Ssam #define DML_USR 0001000 /* usr modem sig, not a real DM bit */ 1446940Ssam #define DML_DSR 0000400 /* data set ready, not a real DM bit */ 1456940Ssam #define DML_RNG 0000200 /* ring */ 1466940Ssam #define DML_CAR 0000100 /* carrier detect */ 1476940Ssam #define DML_CTS 0000040 /* clear to send */ 1486940Ssam #define DML_SR 0000020 /* secondary receive */ 1496940Ssam #define DML_ST 0000010 /* secondary transmit */ 1506940Ssam #define DML_RTS 0000004 /* request to send */ 1516940Ssam #define DML_DTR 0000002 /* data terminal ready */ 1526940Ssam #define DML_LE 0000001 /* line enable */ 1536940Ssam 1546940Ssam /* 1556940Ssam * Local variables for the driver 1566940Ssam */ 1576940Ssam char dmf_speeds[] = 1586940Ssam { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 }; 1596940Ssam 1606940Ssam struct tty dmf_tty[NDMF*8]; 1616940Ssam char dmfsoftCAR[NDMF]; 1628778Sroot #ifndef lint 1638778Sroot int ndmf = NDMF*8; /* used by iostat */ 1648778Sroot #endif 1656940Ssam int dmfact; /* mask of active dmf's */ 1666940Ssam int dmfstart(), ttrstrt(); 1676940Ssam 1686940Ssam #ifdef DMFDMA 1696940Ssam /* 1706940Ssam * The clist space is mapped by the driver onto each UNIBUS. 1716940Ssam * The UBACVT macro converts a clist space address for unibus uban 1726940Ssam * into an i/o space address for the DMA routine. 1736940Ssam */ 1746940Ssam int dmf_ubinfo[MAXNUBA]; /* info about allocated unibus map */ 1756940Ssam static int cbase[MAXNUBA]; /* base address in unibus map */ 1766940Ssam #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 1776940Ssam #endif 1786940Ssam 1796940Ssam /* 1806940Ssam * Routine for configuration to set dmf interrupt. 1816940Ssam */ 1826940Ssam /*ARGSUSED*/ 1836940Ssam dmfprobe(reg, ctlr) 1846940Ssam caddr_t reg; 1856940Ssam int ctlr; 1866940Ssam { 1876940Ssam register int br, cvec; /* these are ``value-result'' */ 1886940Ssam register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg; 1896940Ssam 1906940Ssam #ifdef lint 1916940Ssam br = 0; cvec = br; br = cvec; 1928808Sroot dmfxint(0); dmfrint(0); 1938808Sroot dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint(); 1946940Ssam #endif 1956940Ssam br = 0x15; 1966940Ssam cvec = (uba_hd[numuba].uh_lastiv -= 4*8); 1976940Ssam dmfaddr->dmfccsr0 = cvec >> 2; 1986940Ssam /* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */ 1997412Skre return (sizeof (struct dmfdevice)); 2006940Ssam } 2016940Ssam 2026940Ssam /* 2036940Ssam * Routine called to attach a dmf. 2046940Ssam */ 2056940Ssam dmfattach(ui) 2066940Ssam struct uba_device *ui; 2076940Ssam { 2086940Ssam 2096940Ssam dmfsoftCAR[ui->ui_unit] = ui->ui_flags; 2106940Ssam } 2116940Ssam 2126940Ssam 2136940Ssam /* 2146940Ssam * Open a DMF32 line, mapping the clist onto the uba if this 2156940Ssam * is the first dmf on this uba. Turn on this dmf if this is 2166940Ssam * the first use of it. 2176940Ssam */ 2186940Ssam /*ARGSUSED*/ 2196940Ssam dmfopen(dev, flag) 2206940Ssam dev_t dev; 2216940Ssam { 2226940Ssam register struct tty *tp; 2236940Ssam register int unit, dmf; 2246940Ssam register struct dmfdevice *addr; 2256940Ssam register struct uba_device *ui; 2266940Ssam int s; 2276940Ssam 2286940Ssam unit = minor(dev); 2296940Ssam dmf = unit >> 3; 2308567Sroot if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0) 2318567Sroot return (ENXIO); 2326940Ssam tp = &dmf_tty[unit]; 2338567Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2348567Sroot return (EBUSY); 2356940Ssam addr = (struct dmfdevice *)ui->ui_addr; 2366940Ssam tp->t_addr = (caddr_t)addr; 2376940Ssam tp->t_oproc = dmfstart; 2386971Ssam tp->t_state |= TS_WOPEN; 2396940Ssam /* 2406940Ssam * While setting up state for this uba and this dmf, 2416940Ssam * block uba resets which can clear the state. 2426940Ssam */ 2436940Ssam s = spl5(); 2446940Ssam #ifdef DMFDMA 2456940Ssam if (dmf_ubinfo[ui->ui_ubanum] == 0) { 2466940Ssam dmf_ubinfo[ui->ui_ubanum] = 2476940Ssam uballoc(ui->ui_ubanum, (caddr_t)cfree, 2486940Ssam nclist*sizeof(struct cblock), 0); 2496940Ssam cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff; 2506940Ssam } 2516940Ssam #endif 2526940Ssam if ((dmfact&(1<<dmf)) == 0) { 2536940Ssam addr->dmfcsr |= DMF_IE; 2546940Ssam dmfact |= (1<<dmf); 2556940Ssam addr->dmfrsp = 1; /* DON'T KNOW WHAT TO SET IT TO YET */ 2566940Ssam } 2576940Ssam splx(s); 2586940Ssam /* 2596940Ssam * If this is first open, initialze tty state to default. 2606940Ssam */ 2616971Ssam if ((tp->t_state&TS_ISOPEN) == 0) { 2626940Ssam ttychars(tp); 2636940Ssam if (tp->t_ispeed == 0) { 2646940Ssam tp->t_ispeed = B300; 2656940Ssam tp->t_ospeed = B300; 2666940Ssam tp->t_flags = ODDP|EVENP|ECHO; 2676940Ssam } 2686940Ssam dmfparam(unit); 2696940Ssam } 2706940Ssam /* 2716940Ssam * Wait for carrier, then process line discipline specific open. 2726940Ssam */ 2736940Ssam if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) || 2746940Ssam (dmfsoftCAR[dmf] & (1<<(unit&07)))) 2756971Ssam tp->t_state |= TS_CARR_ON; 2766940Ssam s = spl5(); 2776971Ssam while ((tp->t_state & TS_CARR_ON) == 0) { 2786971Ssam tp->t_state |= TS_WOPEN; 2796940Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 2806940Ssam } 2816940Ssam splx(s); 2828567Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 2836940Ssam } 2846940Ssam 2856940Ssam /* 2866940Ssam * Close a DMF32 line. 2876940Ssam */ 2886940Ssam /*ARGSUSED*/ 2896940Ssam dmfclose(dev, flag) 2906940Ssam dev_t dev; 2916940Ssam int flag; 2926940Ssam { 2936940Ssam register struct tty *tp; 2946940Ssam register unit; 2956940Ssam 2966940Ssam unit = minor(dev); 2976940Ssam tp = &dmf_tty[unit]; 2986940Ssam (*linesw[tp->t_line].l_close)(tp); 2998702Sroot (void) dmfmctl(unit, DMF_BRK, DMBIC); 3006971Ssam if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 3018702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 3026940Ssam ttyclose(tp); 3036940Ssam } 3046940Ssam 3057726Sroot dmfread(dev, uio) 3066940Ssam dev_t dev; 3077726Sroot struct uio *uio; 3086940Ssam { 3096940Ssam register struct tty *tp; 3106940Ssam 3116940Ssam tp = &dmf_tty[minor(dev)]; 3127726Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 3136940Ssam } 3146940Ssam 3157832Sroot dmfwrite(dev, uio) 3166940Ssam dev_t dev; 3177832Sroot struct uio *uio; 3186940Ssam { 3196940Ssam register struct tty *tp; 3206940Ssam 3216940Ssam tp = &dmf_tty[minor(dev)]; 3228530Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 3236940Ssam } 3246940Ssam 3256940Ssam /* 3266940Ssam * DMF32 receiver interrupt. 3276940Ssam */ 3286940Ssam dmfrint(dmf) 3296940Ssam int dmf; 3306940Ssam { 3316940Ssam register struct tty *tp; 3326940Ssam register c; 3336940Ssam register struct dmfdevice *addr; 3346940Ssam register struct tty *tp0; 3356940Ssam register struct uba_device *ui; 3366940Ssam int overrun = 0; 3376940Ssam 3386940Ssam ui = dmfinfo[dmf]; 3396940Ssam if (ui == 0 || ui->ui_alive == 0) 3406940Ssam return; 3416940Ssam addr = (struct dmfdevice *)ui->ui_addr; 3426940Ssam tp0 = &dmf_tty[dmf<<3]; 3436940Ssam /* 3446940Ssam * Loop fetching characters from the silo for this 3456940Ssam * dmf until there are no more in the silo. 3466940Ssam */ 3476940Ssam while ((c = addr->dmfrbuf) < 0) { 3486940Ssam tp = tp0 + ((c>>8)&07); 3496940Ssam if (c & DMF_DSC) { 3506940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07); 3516940Ssam if (addr->dmfrms & DMF_CAR) { 3526971Ssam if ((tp->t_state & TS_CARR_ON) == 0) { 3536940Ssam wakeup((caddr_t)&tp->t_rawq); 3546971Ssam tp->t_state |= TS_CARR_ON; 3556940Ssam } 3566940Ssam } else { 3576971Ssam if (tp->t_state & TS_CARR_ON) { 3586940Ssam gsignal(tp->t_pgrp, SIGHUP); 3596940Ssam gsignal(tp->t_pgrp, SIGCONT); 3606940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | 3616940Ssam ((c>>8)&07); 3626940Ssam addr->dmftms = 0; 3636940Ssam flushtty(tp, FREAD|FWRITE); 3646940Ssam } 3656971Ssam tp->t_state &= ~TS_CARR_ON; 3666940Ssam } 3676940Ssam continue; 3686940Ssam } 3696971Ssam if ((tp->t_state&TS_ISOPEN)==0) { 3706940Ssam wakeup((caddr_t)tp); 3716940Ssam continue; 3726940Ssam } 3736940Ssam if (c & DMF_PE) 3746940Ssam if ((tp->t_flags&(EVENP|ODDP))==EVENP 3756940Ssam || (tp->t_flags&(EVENP|ODDP))==ODDP ) 3766940Ssam continue; 3776940Ssam if ((c & DMF_DO) && overrun == 0) { 3786940Ssam printf("dmf%d: silo overflow\n", dmf); 3796940Ssam overrun = 1; 3806940Ssam } 3816940Ssam if (c & DMF_FE) 3826940Ssam /* 3836940Ssam * At framing error (break) generate 3846940Ssam * a null (in raw mode, for getty), or a 3856940Ssam * interrupt (in cooked/cbreak mode). 3866940Ssam */ 3876940Ssam if (tp->t_flags&RAW) 3886940Ssam c = 0; 3896940Ssam else 3909550Ssam c = tp->t_intrc; 3916940Ssam #if NBK > 0 3926940Ssam if (tp->t_line == NETLDISC) { 3936940Ssam c &= 0177; 3946940Ssam BKINPUT(c, tp); 3956940Ssam } else 3966940Ssam #endif 3976940Ssam (*linesw[tp->t_line].l_rint)(c, tp); 3986940Ssam } 3996940Ssam } 4006940Ssam 4016940Ssam /* 4026940Ssam * Ioctl for DMF32. 4036940Ssam */ 4046940Ssam /*ARGSUSED*/ 4057630Ssam dmfioctl(dev, cmd, data, flag) 4066940Ssam dev_t dev; 4077630Ssam caddr_t data; 4086940Ssam { 4096940Ssam register struct tty *tp; 4106940Ssam register int unit = minor(dev); 4118567Sroot int error; 4126940Ssam 4136940Ssam tp = &dmf_tty[unit]; 4148567Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 4158567Sroot if (error >= 0) 4168567Sroot return (error); 4178567Sroot error = ttioctl(tp, cmd, data, flag); 4188567Sroot if (error >= 0) { 4197630Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 4206940Ssam dmfparam(unit); 4218567Sroot return (error); 4228567Sroot } 4238567Sroot switch (cmd) { 4246940Ssam 4256940Ssam case TIOCSBRK: 4268702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIS); 4276940Ssam break; 4287630Ssam 4296940Ssam case TIOCCBRK: 4308702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIC); 4316940Ssam break; 4327630Ssam 4336940Ssam case TIOCSDTR: 4348702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS); 4356940Ssam break; 4367630Ssam 4376940Ssam case TIOCCDTR: 4388702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC); 4396940Ssam break; 4407630Ssam 4416940Ssam case TIOCMSET: 4428702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET); 4436940Ssam break; 4447630Ssam 4456940Ssam case TIOCMBIS: 4468702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS); 4476940Ssam break; 4487630Ssam 4496940Ssam case TIOCMBIC: 4508702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC); 4516940Ssam break; 4527630Ssam 4536940Ssam case TIOCMGET: 4547630Ssam *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET)); 4556940Ssam break; 4567630Ssam 4576940Ssam default: 4588567Sroot return (ENOTTY); 4596940Ssam } 4608567Sroot return (0); 4616940Ssam } 4626940Ssam 4636940Ssam dmtodmf(bits) 4646940Ssam register int bits; 4656940Ssam { 4666940Ssam register int b; 4676940Ssam 4686940Ssam b = bits & 012; 4696940Ssam if (bits & DML_ST) b |= DMF_RATE; 4706940Ssam if (bits & DML_RTS) b |= DMF_RTS; 4716940Ssam if (bits & DML_USR) b |= DMF_USRW; 4726940Ssam return(b); 4736940Ssam } 4746940Ssam 4756940Ssam dmftodm(bits) 4766940Ssam register int bits; 4776940Ssam { 4786940Ssam register int b; 4796940Ssam 4806940Ssam b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE; 4816940Ssam if (bits & DMF_USRR) b |= DML_USR; 4826940Ssam if (bits & DMF_RTS) b |= DML_RTS; 4836940Ssam return(b); 4846940Ssam } 4856940Ssam 4866940Ssam 4876940Ssam /* 4886940Ssam * Set parameters from open or stty into the DMF hardware 4896940Ssam * registers. 4906940Ssam */ 4916940Ssam dmfparam(unit) 4926940Ssam register int unit; 4936940Ssam { 4946940Ssam register struct tty *tp; 4956940Ssam register struct dmfdevice *addr; 4966940Ssam register int lpar, lcr; 4976940Ssam int s; 4986940Ssam 4996940Ssam tp = &dmf_tty[unit]; 5006940Ssam addr = (struct dmfdevice *)tp->t_addr; 5016940Ssam /* 5026940Ssam * Block interrupts so parameters will be set 5036940Ssam * before the line interrupts. 5046940Ssam */ 5056940Ssam s = spl5(); 5066940Ssam addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE; 5076940Ssam if ((tp->t_ispeed)==0) { 5086971Ssam tp->t_state |= TS_HUPCLS; 5098702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 5106940Ssam return; 5116940Ssam } 5126940Ssam lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8); 5136940Ssam lcr = DMFLCR_ENA; 5146940Ssam if ((tp->t_ispeed) == B134) 5156940Ssam lpar |= BITS6|PENABLE; 5169550Ssam else if (tp->t_flags & (RAW|LITOUT)) 5176940Ssam lpar |= BITS8; 5186940Ssam else { 5196940Ssam lpar |= BITS7|PENABLE; 5206940Ssam /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */ 5216940Ssam } 5226940Ssam if ((tp->t_flags&EVENP) == 0) 5236940Ssam lpar |= OPAR; 5246940Ssam if ((tp->t_ospeed) == B110) 5256940Ssam lpar |= TWOSB; 5266940Ssam lpar |= (unit&07); 5276940Ssam addr->dmflpr = lpar; 5286940Ssam addr->dmflcr = lcr; 5296940Ssam splx(s); 5306940Ssam } 5316940Ssam 5326940Ssam /* 5336940Ssam * DMF32 transmitter interrupt. 5346940Ssam * Restart the idle line. 5356940Ssam */ 5366940Ssam dmfxint(dmf) 5376940Ssam int dmf; 5386940Ssam { 5396940Ssam register struct tty *tp; 5406940Ssam register struct dmfdevice *addr; 5416940Ssam register struct uba_device *ui; 5426940Ssam register int unit, t; 5436940Ssam #ifdef DMFDMA 5446940Ssam short cntr; 5456940Ssam #endif 5466940Ssam 5476940Ssam ui = dmfinfo[dmf]; 5486940Ssam addr = (struct dmfdevice *)ui->ui_addr; 5496940Ssam while ((t = addr->dmfcsr) & DMF_TI) { 5506940Ssam unit = dmf*8 + ((t>>8)&07); 5516940Ssam tp = &dmf_tty[unit]; 5526971Ssam tp->t_state &= ~TS_BUSY; 5536940Ssam if (t & DMF_NXM) { 5546940Ssam printf("dmf%d: NXM line %d\n", dmf, unit&7); 5556940Ssam /* SHOULD RESTART OR SOMETHING... */ 5566940Ssam } 5576971Ssam if (tp->t_state&TS_FLUSH) 5586971Ssam tp->t_state &= ~TS_FLUSH; 5596940Ssam #ifdef DMFDMA 5606940Ssam else { 5616940Ssam addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07); 5626940Ssam if (addr->dmftsc == 0) { 5636940Ssam /* 5646940Ssam * Do arithmetic in a short to make up 5656940Ssam * for lost 16&17 bits. 5666940Ssam */ 5676940Ssam addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07); 5686940Ssam cntr = addr->dmftba - 5696940Ssam UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 5706940Ssam ndflush(&tp->t_outq, (int)cntr); 5716940Ssam } 5726940Ssam } 5736940Ssam #endif 5746940Ssam if (tp->t_line) 5756940Ssam (*linesw[tp->t_line].l_start)(tp); 5766940Ssam else 5776940Ssam dmfstart(tp); 5786940Ssam } 5796940Ssam } 5806940Ssam 5816940Ssam /* 5826940Ssam * Start (restart) transmission on the given DMF32 line. 5836940Ssam */ 5846940Ssam dmfstart(tp) 5856940Ssam register struct tty *tp; 5866940Ssam { 5876940Ssam register struct dmfdevice *addr; 5888607Sroot register int unit, nch; 5896940Ssam int s; 5906940Ssam 5916940Ssam unit = minor(tp->t_dev); 5926940Ssam unit &= 07; 5936940Ssam addr = (struct dmfdevice *)tp->t_addr; 5946940Ssam 5956940Ssam /* 5966940Ssam * Must hold interrupts in following code to prevent 5976940Ssam * state of the tp from changing. 5986940Ssam */ 5996940Ssam s = spl5(); 6006940Ssam /* 6016940Ssam * If it's currently active, or delaying, no need to do anything. 6026940Ssam */ 6036971Ssam if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 6046940Ssam goto out; 6056940Ssam /* 6066940Ssam * If there are still characters in the silo, 6076940Ssam * just reenable the transmitter. 6086940Ssam */ 6096940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 6106940Ssam if (addr->dmftsc) { 6116940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 6126940Ssam addr->dmflcr |= DMF_TE; 6136971Ssam tp->t_state |= TS_BUSY; 6146940Ssam goto out; 6156940Ssam } 6166940Ssam /* 6176940Ssam * If there are sleepers, and output has drained below low 6186940Ssam * water mark, wake up the sleepers. 6196940Ssam */ 6206971Ssam if ((tp->t_state&TS_ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 6216971Ssam tp->t_state &= ~TS_ASLEEP; 6226963Ssam wakeup((caddr_t)&tp->t_outq); 6236940Ssam } 6246940Ssam /* 6256940Ssam * Now restart transmission unless the output queue is 6266940Ssam * empty. 6276940Ssam */ 6286940Ssam if (tp->t_outq.c_cc == 0) 6296940Ssam goto out; 6309550Ssam if (tp->t_flags & (RAW|LITOUT)) 6316940Ssam nch = ndqb(&tp->t_outq, 0); 6326940Ssam else { 6336940Ssam nch = ndqb(&tp->t_outq, 0200); 6346940Ssam /* 6356940Ssam * If first thing on queue is a delay process it. 6366940Ssam */ 6376940Ssam if (nch == 0) { 6386940Ssam nch = getc(&tp->t_outq); 6396940Ssam timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 6406971Ssam tp->t_state |= TS_TIMEOUT; 6416940Ssam goto out; 6426940Ssam } 6436940Ssam } 6446940Ssam /* 6456940Ssam * If characters to transmit, restart transmission. 6466940Ssam */ 6476940Ssam if (nch) { 6486940Ssam #ifdef DMFDMA 6496940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 6506940Ssam addr->dmflcr |= DMF_TE; 6516940Ssam car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); 6526940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; 6536940Ssam addr->dmftba = car; 6546940Ssam addr->dmftcc = ((car>>2)&0xc000) | nch; 6556940Ssam #else 6566940Ssam register char *cp = tp->t_outq.c_cf; 6576940Ssam register int i; 6586940Ssam 6596940Ssam nch = MIN(nch, DMF_SILOCNT); 6606940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 6616940Ssam addr->dmflcr |= DMF_TE; 6626940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 6636940Ssam for (i = 0; i < nch; i++) 6646940Ssam addr->dmftbuf = *cp++; 6656940Ssam ndflush(&tp->t_outq, nch); 6666940Ssam #endif 6676971Ssam tp->t_state |= TS_BUSY; 6686940Ssam } 6696940Ssam out: 6706940Ssam splx(s); 6716940Ssam } 6726940Ssam 6736940Ssam /* 6746940Ssam * Stop output on a line, e.g. for ^S/^Q or output flush. 6756940Ssam */ 6766940Ssam /*ARGSUSED*/ 6776940Ssam dmfstop(tp, flag) 6786940Ssam register struct tty *tp; 6796940Ssam { 6806940Ssam register struct dmfdevice *addr; 6816940Ssam register int unit, s; 6826940Ssam 6836940Ssam addr = (struct dmfdevice *)tp->t_addr; 6846940Ssam /* 6856940Ssam * Block input/output interrupts while messing with state. 6866940Ssam */ 6876940Ssam s = spl5(); 6886971Ssam if (tp->t_state & TS_BUSY) { 6896940Ssam /* 6906940Ssam * Device is transmitting; stop output 6916940Ssam * by selecting the line and disabling 6926940Ssam * the transmitter. If this is a flush 6936940Ssam * request then flush the output silo, 6946940Ssam * otherwise we will pick up where we 6956940Ssam * left off by enabling the transmitter. 6966940Ssam */ 6976940Ssam unit = minor(tp->t_dev); 6986940Ssam addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE; 6996940Ssam addr->dmflcr &= ~DMF_TE; 7006971Ssam if ((tp->t_state&TS_TTSTOP)==0) { 7016971Ssam tp->t_state |= TS_FLUSH; 7026940Ssam addr->dmflcr |= DMF_FLUSH; 7036940Ssam } else 7046971Ssam tp->t_state &= ~TS_BUSY; 7056940Ssam } 7066940Ssam splx(s); 7076940Ssam } 7086940Ssam 7096940Ssam /* 7106940Ssam * DMF32 modem control 7116940Ssam */ 7126940Ssam dmfmctl(dev, bits, how) 7136940Ssam dev_t dev; 7146940Ssam int bits, how; 7156940Ssam { 7166940Ssam register struct dmfdevice *dmfaddr; 7176940Ssam register int unit, mbits, lcr; 7186940Ssam int s; 7196940Ssam 7206940Ssam unit = minor(dev); 7216940Ssam dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr); 7226940Ssam unit &= 07; 7236940Ssam s = spl5(); 7246940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 7256940Ssam mbits = dmfaddr->dmfrms << 8; 7266940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 7276940Ssam mbits |= dmfaddr->dmftms; 7286940Ssam lcr = dmfaddr->dmflcr; 7296940Ssam switch (how) { 7306940Ssam case DMSET: 7316940Ssam mbits = bits; 7326940Ssam break; 7336940Ssam 7346940Ssam case DMBIS: 7356940Ssam mbits |= bits; 7366940Ssam break; 7376940Ssam 7386940Ssam case DMBIC: 7396940Ssam mbits &= ~bits; 7406940Ssam break; 7416940Ssam 7426940Ssam case DMGET: 7436940Ssam (void) splx(s); 7446940Ssam return(mbits); 7456940Ssam } 7466940Ssam dmfaddr->dmftms = mbits&037; 7476940Ssam if (mbits & DMF_BRK) 7486940Ssam lcr |= DMF_RBRK; 7496940Ssam else 7506940Ssam lcr &= ~DMF_RBRK; 7516940Ssam dmfaddr->dmflcr = lcr; 7526940Ssam (void) splx(s); 7536940Ssam return(mbits); 7546940Ssam } 7556940Ssam 7566940Ssam /* 7576940Ssam * Reset state of driver if UBA reset was necessary. 7586940Ssam * Reset the csr, lpr, and lcr registers on open lines, and 7596940Ssam * restart transmitters. 7606940Ssam */ 7616940Ssam dmfreset(uban) 7626940Ssam int uban; 7636940Ssam { 7646940Ssam register int dmf, unit; 7656940Ssam register struct tty *tp; 7666940Ssam register struct uba_device *ui; 7676940Ssam register struct dmfdevice *addr; 7686940Ssam int i; 7696940Ssam 7706940Ssam #ifdef DMFDMA 7716940Ssam if (dmf_ubinfo[uban] == 0) 7726940Ssam return; 7736940Ssam dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 7746940Ssam nclist*sizeof (struct cblock), 0); 7756940Ssam cbase[uban] = dmf_ubinfo[uban]&0x3ffff; 7766940Ssam #endif 7776940Ssam for (dmf = 0; dmf < NDMF; dmf++) { 7786940Ssam ui = dmfinfo[dmf]; 7796940Ssam if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 7806940Ssam continue; 7816940Ssam printf(" dmf%d", dmf); 7826940Ssam addr = (struct dmfdevice *)ui->ui_addr; 7836940Ssam addr->dmfcsr = DMF_IE; 7846940Ssam addr->dmfrsp = 1; 7856940Ssam unit = dmf * 8; 7866940Ssam for (i = 0; i < 8; i++) { 7876940Ssam tp = &dmf_tty[unit]; 7886971Ssam if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 7896940Ssam dmfparam(unit); 7908702Sroot (void) dmfmctl(unit, DMF_ON, DMSET); 7916971Ssam tp->t_state &= ~TS_BUSY; 7926940Ssam dmfstart(tp); 7936940Ssam } 7946940Ssam unit++; 7956940Ssam } 7966940Ssam } 7976940Ssam } 7986940Ssam 7996940Ssam /* stubs for interrupt routines for devices not yet supported */ 8006940Ssam 8016940Ssam dmfsrint() { printf("dmfsrint\n"); } 8026940Ssam 8036940Ssam dmfsxint() { printf("dmfsxint\n"); } 8046940Ssam 8056940Ssam dmfdaint() { printf("dmfdaint\n"); } 8066940Ssam 8076940Ssam dmfdbint() { printf("dmfdbint\n"); } 8086940Ssam 8096940Ssam dmflint() { printf("dmflint\n"); } 8106940Ssam #endif 811