1*17124Sbloom /* dmf.c 6.3 84/08/30 */ 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 */ 189772Ssam #include "../machine/pte.h" 199772Ssam 206940Ssam #include "bk.h" 2116063Skarels #include "uba.h" 22*17124Sbloom #include "param.h" 23*17124Sbloom #include "conf.h" 24*17124Sbloom #include "dir.h" 25*17124Sbloom #include "user.h" 26*17124Sbloom #include "ioctl.h" 27*17124Sbloom #include "tty.h" 28*17124Sbloom #include "map.h" 29*17124Sbloom #include "buf.h" 30*17124Sbloom #include "vm.h" 31*17124Sbloom #include "bkmac.h" 32*17124Sbloom #include "clist.h" 33*17124Sbloom #include "file.h" 34*17124Sbloom #include "uio.h" 356940Ssam 36*17124Sbloom #include "ubareg.h" 37*17124Sbloom #include "ubavar.h" 38*17124Sbloom #include "dmfreg.h" 398473Sroot 406940Ssam /* 416940Ssam * Definition of the driver for the auto-configuration program. 426940Ssam */ 436940Ssam int dmfprobe(), dmfattach(), dmfrint(), dmfxint(); 446940Ssam struct uba_device *dmfinfo[NDMF]; 456940Ssam u_short dmfstd[] = { 0 }; 466940Ssam struct uba_driver dmfdriver = 476940Ssam { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo }; 486940Ssam 496940Ssam /* 506940Ssam * Local variables for the driver 516940Ssam */ 526940Ssam char dmf_speeds[] = 536940Ssam { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 }; 546940Ssam 556940Ssam struct tty dmf_tty[NDMF*8]; 566940Ssam char dmfsoftCAR[NDMF]; 578778Sroot #ifndef lint 588778Sroot int ndmf = NDMF*8; /* used by iostat */ 598778Sroot #endif 606940Ssam int dmfact; /* mask of active dmf's */ 616940Ssam int dmfstart(), ttrstrt(); 626940Ssam 636940Ssam #ifdef DMFDMA 646940Ssam /* 656940Ssam * The clist space is mapped by the driver onto each UNIBUS. 666940Ssam * The UBACVT macro converts a clist space address for unibus uban 676940Ssam * into an i/o space address for the DMA routine. 686940Ssam */ 6916063Skarels int dmf_ubinfo[NUBA]; /* info about allocated unibus map */ 7016063Skarels static int cbase[NUBA]; /* base address in unibus map */ 716940Ssam #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 726940Ssam #endif 736940Ssam 746940Ssam /* 756940Ssam * Routine for configuration to set dmf interrupt. 766940Ssam */ 776940Ssam /*ARGSUSED*/ 786940Ssam dmfprobe(reg, ctlr) 796940Ssam caddr_t reg; 806940Ssam int ctlr; 816940Ssam { 826940Ssam register int br, cvec; /* these are ``value-result'' */ 836940Ssam register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg; 846940Ssam 856940Ssam #ifdef lint 866940Ssam br = 0; cvec = br; br = cvec; 878808Sroot dmfxint(0); dmfrint(0); 888808Sroot dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint(); 896940Ssam #endif 906940Ssam br = 0x15; 916940Ssam cvec = (uba_hd[numuba].uh_lastiv -= 4*8); 926940Ssam dmfaddr->dmfccsr0 = cvec >> 2; 936940Ssam /* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */ 947412Skre return (sizeof (struct dmfdevice)); 956940Ssam } 966940Ssam 976940Ssam /* 986940Ssam * Routine called to attach a dmf. 996940Ssam */ 1006940Ssam dmfattach(ui) 1016940Ssam struct uba_device *ui; 1026940Ssam { 1036940Ssam 1046940Ssam dmfsoftCAR[ui->ui_unit] = ui->ui_flags; 1056940Ssam } 1066940Ssam 1076940Ssam 1086940Ssam /* 1096940Ssam * Open a DMF32 line, mapping the clist onto the uba if this 1106940Ssam * is the first dmf on this uba. Turn on this dmf if this is 1116940Ssam * the first use of it. 1126940Ssam */ 1136940Ssam /*ARGSUSED*/ 1146940Ssam dmfopen(dev, flag) 1156940Ssam dev_t dev; 1166940Ssam { 1176940Ssam register struct tty *tp; 1186940Ssam register int unit, dmf; 1196940Ssam register struct dmfdevice *addr; 1206940Ssam register struct uba_device *ui; 1216940Ssam int s; 1226940Ssam 1236940Ssam unit = minor(dev); 1246940Ssam dmf = unit >> 3; 1258567Sroot if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0) 1268567Sroot return (ENXIO); 1276940Ssam tp = &dmf_tty[unit]; 1288567Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1298567Sroot return (EBUSY); 1306940Ssam addr = (struct dmfdevice *)ui->ui_addr; 1316940Ssam tp->t_addr = (caddr_t)addr; 1326940Ssam tp->t_oproc = dmfstart; 1336971Ssam tp->t_state |= TS_WOPEN; 1346940Ssam /* 1356940Ssam * While setting up state for this uba and this dmf, 1366940Ssam * block uba resets which can clear the state. 1376940Ssam */ 1386940Ssam s = spl5(); 1396940Ssam #ifdef DMFDMA 1406940Ssam if (dmf_ubinfo[ui->ui_ubanum] == 0) { 1416940Ssam dmf_ubinfo[ui->ui_ubanum] = 1426940Ssam uballoc(ui->ui_ubanum, (caddr_t)cfree, 1436940Ssam nclist*sizeof(struct cblock), 0); 1446940Ssam cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff; 1456940Ssam } 1466940Ssam #endif 1476940Ssam if ((dmfact&(1<<dmf)) == 0) { 1486940Ssam addr->dmfcsr |= DMF_IE; 1496940Ssam dmfact |= (1<<dmf); 1506940Ssam addr->dmfrsp = 1; /* DON'T KNOW WHAT TO SET IT TO YET */ 1516940Ssam } 1526940Ssam splx(s); 1536940Ssam /* 1546940Ssam * If this is first open, initialze tty state to default. 1556940Ssam */ 1566971Ssam if ((tp->t_state&TS_ISOPEN) == 0) { 1576940Ssam ttychars(tp); 1586940Ssam if (tp->t_ispeed == 0) { 1596940Ssam tp->t_ispeed = B300; 1606940Ssam tp->t_ospeed = B300; 1616940Ssam tp->t_flags = ODDP|EVENP|ECHO; 1626940Ssam } 1636940Ssam dmfparam(unit); 1646940Ssam } 1656940Ssam /* 1666940Ssam * Wait for carrier, then process line discipline specific open. 1676940Ssam */ 1686940Ssam if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) || 1696940Ssam (dmfsoftCAR[dmf] & (1<<(unit&07)))) 1706971Ssam tp->t_state |= TS_CARR_ON; 1716940Ssam s = spl5(); 1726971Ssam while ((tp->t_state & TS_CARR_ON) == 0) { 1736971Ssam tp->t_state |= TS_WOPEN; 1746940Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 1756940Ssam } 1766940Ssam splx(s); 1778567Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 1786940Ssam } 1796940Ssam 1806940Ssam /* 1816940Ssam * Close a DMF32 line. 1826940Ssam */ 1836940Ssam /*ARGSUSED*/ 1846940Ssam dmfclose(dev, flag) 1856940Ssam dev_t dev; 1866940Ssam int flag; 1876940Ssam { 1886940Ssam register struct tty *tp; 1896940Ssam register unit; 1906940Ssam 1916940Ssam unit = minor(dev); 1926940Ssam tp = &dmf_tty[unit]; 1936940Ssam (*linesw[tp->t_line].l_close)(tp); 1948702Sroot (void) dmfmctl(unit, DMF_BRK, DMBIC); 1956971Ssam if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 1968702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 1976940Ssam ttyclose(tp); 1986940Ssam } 1996940Ssam 2007726Sroot dmfread(dev, uio) 2016940Ssam dev_t dev; 2027726Sroot struct uio *uio; 2036940Ssam { 2046940Ssam register struct tty *tp; 2056940Ssam 2066940Ssam tp = &dmf_tty[minor(dev)]; 2077726Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 2086940Ssam } 2096940Ssam 2107832Sroot dmfwrite(dev, uio) 2116940Ssam dev_t dev; 2127832Sroot struct uio *uio; 2136940Ssam { 2146940Ssam register struct tty *tp; 2156940Ssam 2166940Ssam tp = &dmf_tty[minor(dev)]; 2178530Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 2186940Ssam } 2196940Ssam 2206940Ssam /* 2216940Ssam * DMF32 receiver interrupt. 2226940Ssam */ 2236940Ssam dmfrint(dmf) 2246940Ssam int dmf; 2256940Ssam { 2266940Ssam register struct tty *tp; 2276940Ssam register c; 2286940Ssam register struct dmfdevice *addr; 2296940Ssam register struct tty *tp0; 2306940Ssam register struct uba_device *ui; 23112449Ssam int overrun = 0, s; 2326940Ssam 2336940Ssam ui = dmfinfo[dmf]; 2346940Ssam if (ui == 0 || ui->ui_alive == 0) 2356940Ssam return; 2366940Ssam addr = (struct dmfdevice *)ui->ui_addr; 2376940Ssam tp0 = &dmf_tty[dmf<<3]; 2386940Ssam /* 2396940Ssam * Loop fetching characters from the silo for this 2406940Ssam * dmf until there are no more in the silo. 2416940Ssam */ 2426940Ssam while ((c = addr->dmfrbuf) < 0) { 2436940Ssam tp = tp0 + ((c>>8)&07); 2446940Ssam if (c & DMF_DSC) { 24512449Ssam s = spl5(); 2466940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07); 2476940Ssam if (addr->dmfrms & DMF_CAR) { 2486971Ssam if ((tp->t_state & TS_CARR_ON) == 0) { 2496940Ssam wakeup((caddr_t)&tp->t_rawq); 2506971Ssam tp->t_state |= TS_CARR_ON; 2516940Ssam } 2526940Ssam } else { 2536971Ssam if (tp->t_state & TS_CARR_ON) { 2546940Ssam gsignal(tp->t_pgrp, SIGHUP); 2556940Ssam gsignal(tp->t_pgrp, SIGCONT); 2566940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | 2576940Ssam ((c>>8)&07); 2586940Ssam addr->dmftms = 0; 25912776Ssam ttyflush(tp, FREAD|FWRITE); 2606940Ssam } 2616971Ssam tp->t_state &= ~TS_CARR_ON; 2626940Ssam } 26312449Ssam splx(s); 2646940Ssam continue; 2656940Ssam } 2666971Ssam if ((tp->t_state&TS_ISOPEN)==0) { 2676940Ssam wakeup((caddr_t)tp); 2686940Ssam continue; 2696940Ssam } 2706940Ssam if (c & DMF_PE) 2716940Ssam if ((tp->t_flags&(EVENP|ODDP))==EVENP 2726940Ssam || (tp->t_flags&(EVENP|ODDP))==ODDP ) 2736940Ssam continue; 2746940Ssam if ((c & DMF_DO) && overrun == 0) { 2756940Ssam printf("dmf%d: silo overflow\n", dmf); 2766940Ssam overrun = 1; 2776940Ssam } 2786940Ssam if (c & DMF_FE) 2796940Ssam /* 2806940Ssam * At framing error (break) generate 2816940Ssam * a null (in raw mode, for getty), or a 2826940Ssam * interrupt (in cooked/cbreak mode). 2836940Ssam */ 2846940Ssam if (tp->t_flags&RAW) 2856940Ssam c = 0; 2866940Ssam else 2879550Ssam c = tp->t_intrc; 2886940Ssam #if NBK > 0 2896940Ssam if (tp->t_line == NETLDISC) { 2906940Ssam c &= 0177; 2916940Ssam BKINPUT(c, tp); 2926940Ssam } else 2936940Ssam #endif 2946940Ssam (*linesw[tp->t_line].l_rint)(c, tp); 2956940Ssam } 2966940Ssam } 2976940Ssam 2986940Ssam /* 2996940Ssam * Ioctl for DMF32. 3006940Ssam */ 3016940Ssam /*ARGSUSED*/ 3027630Ssam dmfioctl(dev, cmd, data, flag) 3036940Ssam dev_t dev; 3047630Ssam caddr_t data; 3056940Ssam { 3066940Ssam register struct tty *tp; 3076940Ssam register int unit = minor(dev); 3088567Sroot int error; 3096940Ssam 3106940Ssam tp = &dmf_tty[unit]; 3118567Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3128567Sroot if (error >= 0) 3138567Sroot return (error); 3148567Sroot error = ttioctl(tp, cmd, data, flag); 3158567Sroot if (error >= 0) { 3167630Ssam if (cmd == TIOCSETP || cmd == TIOCSETN) 3176940Ssam dmfparam(unit); 3188567Sroot return (error); 3198567Sroot } 3208567Sroot switch (cmd) { 3216940Ssam 3226940Ssam case TIOCSBRK: 3238702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIS); 3246940Ssam break; 3257630Ssam 3266940Ssam case TIOCCBRK: 3278702Sroot (void) dmfmctl(dev, DMF_BRK, DMBIC); 3286940Ssam break; 3297630Ssam 3306940Ssam case TIOCSDTR: 3318702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS); 3326940Ssam break; 3337630Ssam 3346940Ssam case TIOCCDTR: 3358702Sroot (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC); 3366940Ssam break; 3377630Ssam 3386940Ssam case TIOCMSET: 3398702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET); 3406940Ssam break; 3417630Ssam 3426940Ssam case TIOCMBIS: 3438702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS); 3446940Ssam break; 3457630Ssam 3466940Ssam case TIOCMBIC: 3478702Sroot (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC); 3486940Ssam break; 3497630Ssam 3506940Ssam case TIOCMGET: 3517630Ssam *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET)); 3526940Ssam break; 3537630Ssam 3546940Ssam default: 3558567Sroot return (ENOTTY); 3566940Ssam } 3578567Sroot return (0); 3586940Ssam } 3596940Ssam 3606940Ssam dmtodmf(bits) 3616940Ssam register int bits; 3626940Ssam { 3636940Ssam register int b; 3646940Ssam 3656940Ssam b = bits & 012; 3666940Ssam if (bits & DML_ST) b |= DMF_RATE; 3676940Ssam if (bits & DML_RTS) b |= DMF_RTS; 3686940Ssam if (bits & DML_USR) b |= DMF_USRW; 3696940Ssam return(b); 3706940Ssam } 3716940Ssam 3726940Ssam dmftodm(bits) 3736940Ssam register int bits; 3746940Ssam { 3756940Ssam register int b; 3766940Ssam 3776940Ssam b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE; 3786940Ssam if (bits & DMF_USRR) b |= DML_USR; 3796940Ssam if (bits & DMF_RTS) b |= DML_RTS; 3806940Ssam return(b); 3816940Ssam } 3826940Ssam 3836940Ssam 3846940Ssam /* 3856940Ssam * Set parameters from open or stty into the DMF hardware 3866940Ssam * registers. 3876940Ssam */ 3886940Ssam dmfparam(unit) 3896940Ssam register int unit; 3906940Ssam { 3916940Ssam register struct tty *tp; 3926940Ssam register struct dmfdevice *addr; 3936940Ssam register int lpar, lcr; 3946940Ssam int s; 3956940Ssam 3966940Ssam tp = &dmf_tty[unit]; 3976940Ssam addr = (struct dmfdevice *)tp->t_addr; 3986940Ssam /* 3996940Ssam * Block interrupts so parameters will be set 4006940Ssam * before the line interrupts. 4016940Ssam */ 4026940Ssam s = spl5(); 4036940Ssam addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE; 4046940Ssam if ((tp->t_ispeed)==0) { 4056971Ssam tp->t_state |= TS_HUPCLS; 4068702Sroot (void) dmfmctl(unit, DMF_OFF, DMSET); 4076940Ssam return; 4086940Ssam } 4096940Ssam lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8); 4106940Ssam lcr = DMFLCR_ENA; 4116940Ssam if ((tp->t_ispeed) == B134) 4126940Ssam lpar |= BITS6|PENABLE; 4139550Ssam else if (tp->t_flags & (RAW|LITOUT)) 4146940Ssam lpar |= BITS8; 4156940Ssam else { 4166940Ssam lpar |= BITS7|PENABLE; 4176940Ssam /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */ 4186940Ssam } 41912450Ssam if (tp->t_flags&EVENP) 42012450Ssam lpar |= EPAR; 4216940Ssam if ((tp->t_ospeed) == B110) 4226940Ssam lpar |= TWOSB; 4236940Ssam lpar |= (unit&07); 4246940Ssam addr->dmflpr = lpar; 42512449Ssam SETLCR(addr, lcr); 4266940Ssam splx(s); 4276940Ssam } 4286940Ssam 4296940Ssam /* 4306940Ssam * DMF32 transmitter interrupt. 4316940Ssam * Restart the idle line. 4326940Ssam */ 4336940Ssam dmfxint(dmf) 4346940Ssam int dmf; 4356940Ssam { 4366940Ssam register struct tty *tp; 4376940Ssam register struct dmfdevice *addr; 4386940Ssam register struct uba_device *ui; 4396940Ssam register int unit, t; 4406940Ssam #ifdef DMFDMA 4416940Ssam short cntr; 44212449Ssam int s; 4436940Ssam #endif 4446940Ssam 4456940Ssam ui = dmfinfo[dmf]; 4466940Ssam addr = (struct dmfdevice *)ui->ui_addr; 4476940Ssam while ((t = addr->dmfcsr) & DMF_TI) { 4486940Ssam unit = dmf*8 + ((t>>8)&07); 4496940Ssam tp = &dmf_tty[unit]; 4506971Ssam tp->t_state &= ~TS_BUSY; 4516940Ssam if (t & DMF_NXM) { 4526940Ssam printf("dmf%d: NXM line %d\n", dmf, unit&7); 4536940Ssam /* SHOULD RESTART OR SOMETHING... */ 4546940Ssam } 4556971Ssam if (tp->t_state&TS_FLUSH) 4566971Ssam tp->t_state &= ~TS_FLUSH; 4576940Ssam #ifdef DMFDMA 4586940Ssam else { 45912449Ssam s = spl5(); 4606940Ssam addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07); 4616940Ssam if (addr->dmftsc == 0) { 4626940Ssam /* 4636940Ssam * Do arithmetic in a short to make up 4646940Ssam * for lost 16&17 bits. 4656940Ssam */ 4666940Ssam addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07); 4676940Ssam cntr = addr->dmftba - 4686940Ssam UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4696940Ssam ndflush(&tp->t_outq, (int)cntr); 4706940Ssam } 47112449Ssam splx(s); 4726940Ssam } 4736940Ssam #endif 4746940Ssam if (tp->t_line) 4756940Ssam (*linesw[tp->t_line].l_start)(tp); 4766940Ssam else 4776940Ssam dmfstart(tp); 4786940Ssam } 4796940Ssam } 4806940Ssam 4816940Ssam /* 4826940Ssam * Start (restart) transmission on the given DMF32 line. 4836940Ssam */ 4846940Ssam dmfstart(tp) 4856940Ssam register struct tty *tp; 4866940Ssam { 4876940Ssam register struct dmfdevice *addr; 4888607Sroot register int unit, nch; 4896940Ssam int s; 4906940Ssam 4916940Ssam unit = minor(tp->t_dev); 4926940Ssam unit &= 07; 4936940Ssam addr = (struct dmfdevice *)tp->t_addr; 4946940Ssam 4956940Ssam /* 4966940Ssam * Must hold interrupts in following code to prevent 4976940Ssam * state of the tp from changing. 4986940Ssam */ 4996940Ssam s = spl5(); 5006940Ssam /* 5016940Ssam * If it's currently active, or delaying, no need to do anything. 5026940Ssam */ 5036971Ssam if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 5046940Ssam goto out; 5056940Ssam /* 5066940Ssam * If there are still characters in the silo, 5076940Ssam * just reenable the transmitter. 5086940Ssam */ 5096940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 5106940Ssam if (addr->dmftsc) { 5116940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 51212449Ssam SETLCR(addr, addr->dmflcr|DMF_TE); 5136971Ssam tp->t_state |= TS_BUSY; 5146940Ssam goto out; 5156940Ssam } 5166940Ssam /* 5176940Ssam * If there are sleepers, and output has drained below low 5186940Ssam * water mark, wake up the sleepers. 5196940Ssam */ 5206971Ssam if ((tp->t_state&TS_ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 5216971Ssam tp->t_state &= ~TS_ASLEEP; 5226963Ssam wakeup((caddr_t)&tp->t_outq); 5236940Ssam } 5246940Ssam /* 5256940Ssam * Now restart transmission unless the output queue is 5266940Ssam * empty. 5276940Ssam */ 5286940Ssam if (tp->t_outq.c_cc == 0) 5296940Ssam goto out; 5309550Ssam if (tp->t_flags & (RAW|LITOUT)) 5316940Ssam nch = ndqb(&tp->t_outq, 0); 5326940Ssam else { 5336940Ssam nch = ndqb(&tp->t_outq, 0200); 5346940Ssam /* 5356940Ssam * If first thing on queue is a delay process it. 5366940Ssam */ 5376940Ssam if (nch == 0) { 5386940Ssam nch = getc(&tp->t_outq); 5396940Ssam timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5406971Ssam tp->t_state |= TS_TIMEOUT; 5416940Ssam goto out; 5426940Ssam } 5436940Ssam } 5446940Ssam /* 5456940Ssam * If characters to transmit, restart transmission. 5466940Ssam */ 5476940Ssam if (nch) { 5486940Ssam #ifdef DMFDMA 5496940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 55012449Ssam SETLCR(addr, addr->dmflcr|DMF_TE); 5516940Ssam car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); 5526940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; 5536940Ssam addr->dmftba = car; 5546940Ssam addr->dmftcc = ((car>>2)&0xc000) | nch; 5556940Ssam #else 5566940Ssam register char *cp = tp->t_outq.c_cf; 5576940Ssam register int i; 5586940Ssam 5596940Ssam nch = MIN(nch, DMF_SILOCNT); 5606940Ssam addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 56112449Ssam SETLCR(addr, addr->dmflcr|DMF_TE); 5626940Ssam addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 5636940Ssam for (i = 0; i < nch; i++) 5646940Ssam addr->dmftbuf = *cp++; 5656940Ssam ndflush(&tp->t_outq, nch); 5666940Ssam #endif 5676971Ssam tp->t_state |= TS_BUSY; 5686940Ssam } 5696940Ssam out: 5706940Ssam splx(s); 5716940Ssam } 5726940Ssam 5736940Ssam /* 5746940Ssam * Stop output on a line, e.g. for ^S/^Q or output flush. 5756940Ssam */ 5766940Ssam /*ARGSUSED*/ 5776940Ssam dmfstop(tp, flag) 5786940Ssam register struct tty *tp; 5796940Ssam { 5806940Ssam register struct dmfdevice *addr; 5816940Ssam register int unit, s; 5826940Ssam 5836940Ssam addr = (struct dmfdevice *)tp->t_addr; 5846940Ssam /* 5856940Ssam * Block input/output interrupts while messing with state. 5866940Ssam */ 5876940Ssam s = spl5(); 5886971Ssam if (tp->t_state & TS_BUSY) { 5896940Ssam /* 5906940Ssam * Device is transmitting; stop output 5916940Ssam * by selecting the line and disabling 5926940Ssam * the transmitter. If this is a flush 5936940Ssam * request then flush the output silo, 5946940Ssam * otherwise we will pick up where we 5956940Ssam * left off by enabling the transmitter. 5966940Ssam */ 5976940Ssam unit = minor(tp->t_dev); 5986940Ssam addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE; 59912449Ssam SETLCR(addr, addr->dmflcr &~ DMF_TE); 6006971Ssam if ((tp->t_state&TS_TTSTOP)==0) { 6016971Ssam tp->t_state |= TS_FLUSH; 60212449Ssam SETLCR(addr, addr->dmflcr|DMF_FLUSH); 6036940Ssam } else 6046971Ssam tp->t_state &= ~TS_BUSY; 6056940Ssam } 6066940Ssam splx(s); 6076940Ssam } 6086940Ssam 6096940Ssam /* 6106940Ssam * DMF32 modem control 6116940Ssam */ 6126940Ssam dmfmctl(dev, bits, how) 6136940Ssam dev_t dev; 6146940Ssam int bits, how; 6156940Ssam { 6166940Ssam register struct dmfdevice *dmfaddr; 6176940Ssam register int unit, mbits, lcr; 6186940Ssam int s; 6196940Ssam 6206940Ssam unit = minor(dev); 6216940Ssam dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr); 6226940Ssam unit &= 07; 6236940Ssam s = spl5(); 6246940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; 6256940Ssam mbits = dmfaddr->dmfrms << 8; 6266940Ssam dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit; 6276940Ssam mbits |= dmfaddr->dmftms; 6286940Ssam lcr = dmfaddr->dmflcr; 6296940Ssam switch (how) { 6306940Ssam case DMSET: 63112449Ssam mbits = (mbits &0xff00) | bits; 6326940Ssam break; 6336940Ssam 6346940Ssam case DMBIS: 6356940Ssam mbits |= bits; 6366940Ssam break; 6376940Ssam 6386940Ssam case DMBIC: 6396940Ssam mbits &= ~bits; 6406940Ssam break; 6416940Ssam 6426940Ssam case DMGET: 6436940Ssam (void) splx(s); 6446940Ssam return(mbits); 6456940Ssam } 6466940Ssam if (mbits & DMF_BRK) 6476940Ssam lcr |= DMF_RBRK; 6486940Ssam else 6496940Ssam lcr &= ~DMF_RBRK; 65012449Ssam lcr = ((mbits & 037) << 8) | (lcr & 0xff); 65112449Ssam dmfaddr->dmfun.dmfirw = lcr; 6526940Ssam (void) splx(s); 6536940Ssam return(mbits); 6546940Ssam } 6556940Ssam 6566940Ssam /* 6576940Ssam * Reset state of driver if UBA reset was necessary. 6586940Ssam * Reset the csr, lpr, and lcr registers on open lines, and 6596940Ssam * restart transmitters. 6606940Ssam */ 6616940Ssam dmfreset(uban) 6626940Ssam int uban; 6636940Ssam { 6646940Ssam register int dmf, unit; 6656940Ssam register struct tty *tp; 6666940Ssam register struct uba_device *ui; 6676940Ssam register struct dmfdevice *addr; 6686940Ssam int i; 6696940Ssam 6706940Ssam #ifdef DMFDMA 6716940Ssam if (dmf_ubinfo[uban] == 0) 6726940Ssam return; 6736940Ssam dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6746940Ssam nclist*sizeof (struct cblock), 0); 6756940Ssam cbase[uban] = dmf_ubinfo[uban]&0x3ffff; 6766940Ssam #endif 6776940Ssam for (dmf = 0; dmf < NDMF; dmf++) { 6786940Ssam ui = dmfinfo[dmf]; 6796940Ssam if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6806940Ssam continue; 6816940Ssam printf(" dmf%d", dmf); 6826940Ssam addr = (struct dmfdevice *)ui->ui_addr; 6836940Ssam addr->dmfcsr = DMF_IE; 6846940Ssam addr->dmfrsp = 1; 6856940Ssam unit = dmf * 8; 6866940Ssam for (i = 0; i < 8; i++) { 6876940Ssam tp = &dmf_tty[unit]; 6886971Ssam if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6896940Ssam dmfparam(unit); 6908702Sroot (void) dmfmctl(unit, DMF_ON, DMSET); 6916971Ssam tp->t_state &= ~TS_BUSY; 6926940Ssam dmfstart(tp); 6936940Ssam } 6946940Ssam unit++; 6956940Ssam } 6966940Ssam } 6976940Ssam } 6986940Ssam 6996940Ssam /* stubs for interrupt routines for devices not yet supported */ 7006940Ssam 7016940Ssam dmfsrint() { printf("dmfsrint\n"); } 7026940Ssam 7036940Ssam dmfsxint() { printf("dmfsxint\n"); } 7046940Ssam 7056940Ssam dmfdaint() { printf("dmfdaint\n"); } 7066940Ssam 7076940Ssam dmfdbint() { printf("dmfdbint\n"); } 7086940Ssam 7096940Ssam dmflint() { printf("dmflint\n"); } 7106940Ssam #endif 711