123320Smckusick /* 229209Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323320Smckusick * All rights reserved. The Berkeley software License Agreement 423320Smckusick * specifies the terms and conditions for redistribution. 523320Smckusick * 6*30349Skarels * @(#)dh.c 7.4 (Berkeley) 12/30/86 723320Smckusick */ 813Sbill 91934Swnj #include "dh.h" 102643Swnj #if NDH > 0 1113Sbill /* 122479Swnj * DH-11/DM-11 driver 1313Sbill */ 149771Ssam #include "../machine/pte.h" 159771Ssam 162730Swnj #include "bk.h" 1716062Skarels #include "uba.h" 1817122Sbloom #include "param.h" 1917122Sbloom #include "conf.h" 2017122Sbloom #include "dir.h" 2117122Sbloom #include "user.h" 2217122Sbloom #include "proc.h" 2317122Sbloom #include "ioctl.h" 2417122Sbloom #include "tty.h" 2517122Sbloom #include "map.h" 2617122Sbloom #include "buf.h" 2717122Sbloom #include "vm.h" 2817122Sbloom #include "kernel.h" 2918311Sralph #include "syslog.h" 308472Sroot 3117122Sbloom #include "ubareg.h" 3217122Sbloom #include "ubavar.h" 3317122Sbloom #include "dhreg.h" 3417122Sbloom #include "dmreg.h" 358472Sroot 3617122Sbloom #include "bkmac.h" 3717122Sbloom #include "clist.h" 3817122Sbloom #include "file.h" 3917122Sbloom #include "uio.h" 4013Sbill 412468Swnj /* 422479Swnj * Definition of the driver for the auto-configuration program. 432479Swnj * There is one definition for the dh and one for the dm. 442468Swnj */ 4516190Skarels int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer(); 462974Swnj struct uba_device *dhinfo[NDH]; 472395Swnj u_short dhstd[] = { 0 }; 482395Swnj struct uba_driver dhdriver = 492605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 502395Swnj 512605Swnj int dmprobe(), dmattach(), dmintr(); 522974Swnj struct uba_device *dminfo[NDH]; 532479Swnj u_short dmstd[] = { 0 }; 542479Swnj struct uba_driver dmdriver = 552605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 5613Sbill 576615Ssam #ifndef PORTSELECTOR 5825394Skarels #define ISPEED B9600 596615Ssam #define IFLAGS (EVENP|ODDP|ECHO) 606615Ssam #else 616615Ssam #define ISPEED B4800 626615Ssam #define IFLAGS (EVENP|ODDP) 636615Ssam #endif 646615Ssam 6516190Skarels #define FASTTIMER (hz/30) /* scan rate with silos on */ 6616190Skarels 6713Sbill /* 682479Swnj * Local variables for the driver 6913Sbill */ 702643Swnj short dhsar[NDH]; /* software copy of last bar */ 712643Swnj short dhsoftCAR[NDH]; 7213Sbill 732643Swnj struct tty dh11[NDH*16]; 742643Swnj int ndh11 = NDH*16; 752479Swnj int dhact; /* mask of active dh's */ 7616190Skarels int dhsilos; /* mask of dh's with silo in use */ 7716190Skarels int dhchars[NDH]; /* recent input count */ 7816190Skarels int dhrate[NDH]; /* smoothed input count */ 7916190Skarels int dhhighrate = 100; /* silo on if dhchars > dhhighrate */ 8016190Skarels int dhlowrate = 75; /* silo off if dhrate < dhlowrate */ 8116190Skarels static short timerstarted; 822479Swnj int dhstart(), ttrstrt(); 8313Sbill 842479Swnj /* 8530322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS. 8630322Skarels * The identity of the board which allocated resources is recorded, 8730322Skarels * so the process may be repeated after UNIBUS resets. 882479Swnj * The UBACVT macro converts a clist space address for unibus uban 892479Swnj * into an i/o space address for the DMA routine. 902479Swnj */ 9130322Skarels int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */ 9230322Skarels int cbase[NUBA]; /* base address of clists in unibus map */ 932479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 9413Sbill 952456Swnj /* 962456Swnj * Routine for configuration to force a dh to interrupt. 972456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 982456Swnj */ 992468Swnj /*ARGSUSED*/ 1002605Swnj dhprobe(reg) 101*30349Skarels p 1022395Swnj caddr_t reg; 1032395Swnj { 1042468Swnj register int br, cvec; /* these are ``value-result'' */ 1052479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1062395Swnj 1072605Swnj #ifdef lint 1082605Swnj br = 0; cvec = br; br = cvec; 1097384Sroot if (ndh11 == 0) ndh11 = 1; 1104932Swnj dhrint(0); dhxint(0); 1112605Swnj #endif 1122696Swnj #ifndef notdef 1132566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1146380Swnj DELAY(1000); 1157384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1162566Swnj dhaddr->un.dhcsr = 0; 1172566Swnj #else 1182456Swnj dhaddr->un.dhcsr = DH_TIE; 1192456Swnj DELAY(5); 1202456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1212421Skre dhaddr->dhbcr = -1; 1222456Swnj dhaddr->dhcar = 0; 1232421Skre dhaddr->dhbar = 1; 1242456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1252421Skre dhaddr->un.dhcsr = 0; 1262456Swnj if (cvec && cvec != 0x200) 1272456Swnj cvec -= 4; /* transmit -> receive */ 1282482Swnj #endif 1297408Skre return (sizeof (struct dhdevice)); 1302395Swnj } 1312395Swnj 1322456Swnj /* 1332605Swnj * Routine called to attach a dh. 1342456Swnj */ 1352605Swnj dhattach(ui) 1362974Swnj struct uba_device *ui; 1372395Swnj { 1382395Swnj 1392566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 14026219Skarels cbase[ui->ui_ubanum] = -1; 14130322Skarels dh_uballoc[ui->ui_unit] = -1; 1422395Swnj } 1432395Swnj 14413Sbill /* 1452479Swnj * Configuration routine to cause a dm to interrupt. 1462479Swnj */ 1472605Swnj dmprobe(reg) 1482605Swnj caddr_t reg; 1492479Swnj { 1502479Swnj register int br, vec; /* value-result */ 1512605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1522479Swnj 1532605Swnj #ifdef lint 1543101Swnj br = 0; vec = br; br = vec; 1556185Ssam dmintr(0); 1562605Swnj #endif 1572479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1582479Swnj DELAY(20); 1592479Swnj dmaddr->dmcsr = 0; 1602605Swnj return (1); 1612479Swnj } 1622479Swnj 1632605Swnj /*ARGSUSED*/ 1642605Swnj dmattach(ui) 1652974Swnj struct uba_device *ui; 1662479Swnj { 1672479Swnj 1682479Swnj /* no local state to set up */ 1692479Swnj } 1702479Swnj 1712479Swnj /* 1722468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1732468Swnj * is the first dh on this uba. Turn on this dh if this is 1742468Swnj * the first use of it. Also do a dmopen to wait for carrier. 17513Sbill */ 17613Sbill /*ARGSUSED*/ 17713Sbill dhopen(dev, flag) 1782395Swnj dev_t dev; 17913Sbill { 18013Sbill register struct tty *tp; 1812395Swnj register int unit, dh; 1822479Swnj register struct dhdevice *addr; 1832974Swnj register struct uba_device *ui; 18413Sbill int s; 18513Sbill 1862395Swnj unit = minor(dev); 1872395Swnj dh = unit >> 4; 1888566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 1898566Sroot return (ENXIO); 1902395Swnj tp = &dh11[unit]; 1918566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1928566Sroot return (EBUSY); 1932479Swnj addr = (struct dhdevice *)ui->ui_addr; 19413Sbill tp->t_addr = (caddr_t)addr; 19513Sbill tp->t_oproc = dhstart; 1965406Swnj tp->t_state |= TS_WOPEN; 1972468Swnj /* 1982468Swnj * While setting up state for this uba and this dh, 1992468Swnj * block uba resets which can clear the state. 2002468Swnj */ 2012468Swnj s = spl5(); 20226219Skarels if (cbase[ui->ui_ubanum] == -1) { 20330322Skarels dh_uballoc[ui->ui_ubanum] = dh; 20430322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, 20530322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); 20613Sbill } 20716190Skarels if (timerstarted == 0) { 20816190Skarels timerstarted++; 20916190Skarels timeout(dhtimer, (caddr_t) 0, hz); 21016190Skarels } 2112456Swnj if ((dhact&(1<<dh)) == 0) { 2122456Swnj addr->un.dhcsr |= DH_IE; 2132468Swnj dhact |= (1<<dh); 21416190Skarels addr->dhsilo = 0; 2152456Swnj } 21613Sbill splx(s); 2172468Swnj /* 21827049Skarels * If this is first open, initialize tty state to default. 2192468Swnj */ 2205406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 22113Sbill ttychars(tp); 22227049Skarels #ifndef PORTSELECTOR 22327049Skarels if (tp->t_ispeed == 0) { 22427049Skarels #else 22527049Skarels tp->t_state |= TS_HUPCLS; 22627049Skarels #endif PORTSELECTOR 22727049Skarels tp->t_ispeed = ISPEED; 22827049Skarels tp->t_ospeed = ISPEED; 22927049Skarels tp->t_flags = IFLAGS; 23027049Skarels #ifndef PORTSELECTOR 23127049Skarels } 23227049Skarels #endif PORTSELECTOR 2332395Swnj dhparam(unit); 23413Sbill } 2352468Swnj /* 2362468Swnj * Wait for carrier, then process line discipline specific open. 2372468Swnj */ 23813Sbill dmopen(dev); 2398566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 24013Sbill } 24113Sbill 24213Sbill /* 2432468Swnj * Close a DH11 line, turning off the DM11. 24413Sbill */ 24513Sbill /*ARGSUSED*/ 24613Sbill dhclose(dev, flag) 2472395Swnj dev_t dev; 2482395Swnj int flag; 24913Sbill { 25013Sbill register struct tty *tp; 2512395Swnj register unit; 25213Sbill 2532395Swnj unit = minor(dev); 2542395Swnj tp = &dh11[unit]; 25513Sbill (*linesw[tp->t_line].l_close)(tp); 2562479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2575406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2582479Swnj dmctl(unit, DML_OFF, DMSET); 25913Sbill ttyclose(tp); 26013Sbill } 26113Sbill 2627725Sroot dhread(dev, uio) 2632395Swnj dev_t dev; 2647725Sroot struct uio *uio; 26513Sbill { 2668490Sroot register struct tty *tp = &dh11[minor(dev)]; 26713Sbill 2687725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 26913Sbill } 27013Sbill 2717831Sroot dhwrite(dev, uio) 2722395Swnj dev_t dev; 2737831Sroot struct uio *uio; 27413Sbill { 2758490Sroot register struct tty *tp = &dh11[minor(dev)]; 27613Sbill 2778490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 27813Sbill } 27913Sbill 28013Sbill /* 28113Sbill * DH11 receiver interrupt. 28213Sbill */ 2832395Swnj dhrint(dh) 2842395Swnj int dh; 28513Sbill { 28613Sbill register struct tty *tp; 2872395Swnj register c; 2882479Swnj register struct dhdevice *addr; 289117Sbill register struct tty *tp0; 2902974Swnj register struct uba_device *ui; 2912924Swnj int overrun = 0; 29213Sbill 2932395Swnj ui = dhinfo[dh]; 2942479Swnj if (ui == 0 || ui->ui_alive == 0) 2952479Swnj return; 2962479Swnj addr = (struct dhdevice *)ui->ui_addr; 2972468Swnj tp0 = &dh11[dh<<4]; 2982468Swnj /* 2992468Swnj * Loop fetching characters from the silo for this 3002468Swnj * dh until there are no more in the silo. 3012468Swnj */ 3022468Swnj while ((c = addr->dhrcr) < 0) { 3032468Swnj tp = tp0 + ((c>>8)&0xf); 30416190Skarels dhchars[dh]++; 3055406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 30625394Skarels wakeup((caddr_t)&tp->t_rawq); 30725394Skarels #ifdef PORTSELECTOR 30825394Skarels if ((tp->t_state&TS_WOPEN) == 0) 3096615Ssam #endif 31025394Skarels continue; 31113Sbill } 3122468Swnj if (c & DH_PE) 31313Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 31413Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 31513Sbill continue; 3162924Swnj if ((c & DH_DO) && overrun == 0) { 31724840Seric log(LOG_WARNING, "dh%d: silo overflow\n", dh); 3182924Swnj overrun = 1; 3192924Swnj } 3202468Swnj if (c & DH_FE) 3212468Swnj /* 3222468Swnj * At framing error (break) generate 3232468Swnj * a null (in raw mode, for getty), or a 3242468Swnj * interrupt (in cooked/cbreak mode). 3252468Swnj */ 32613Sbill if (tp->t_flags&RAW) 3272468Swnj c = 0; 32813Sbill else 3299549Ssam c = tp->t_intrc; 3302730Swnj #if NBK > 0 331139Sbill if (tp->t_line == NETLDISC) { 332117Sbill c &= 0177; 333168Sbill BKINPUT(c, tp); 334117Sbill } else 3352730Swnj #endif 3362468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 33713Sbill } 33813Sbill } 33913Sbill 34013Sbill /* 3412468Swnj * Ioctl for DH11. 34213Sbill */ 34313Sbill /*ARGSUSED*/ 3447629Ssam dhioctl(dev, cmd, data, flag) 3457629Ssam caddr_t data; 34613Sbill { 34713Sbill register struct tty *tp; 3488566Sroot register int unit = minor(dev); 3498566Sroot int error; 35013Sbill 3512395Swnj tp = &dh11[unit]; 3528566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3538566Sroot if (error >= 0) 3548566Sroot return (error); 3558566Sroot error = ttioctl(tp, cmd, data, flag); 3568566Sroot if (error >= 0) { 35717561Sbloom if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 35817561Sbloom cmd == TIOCLBIC || cmd == TIOCLSET) 3592395Swnj dhparam(unit); 3608566Sroot return (error); 3618566Sroot } 3628566Sroot switch (cmd) { 3637629Ssam 364168Sbill case TIOCSBRK: 3652479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 366168Sbill break; 3677629Ssam 368168Sbill case TIOCCBRK: 3692479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 370168Sbill break; 3717629Ssam 372168Sbill case TIOCSDTR: 3732479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 374168Sbill break; 3757629Ssam 376168Sbill case TIOCCDTR: 3772479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 378168Sbill break; 3797629Ssam 380168Sbill default: 3818566Sroot return (ENOTTY); 382168Sbill } 3838566Sroot return (0); 38413Sbill } 38513Sbill 38613Sbill /* 38713Sbill * Set parameters from open or stty into the DH hardware 38813Sbill * registers. 38913Sbill */ 3902395Swnj dhparam(unit) 3912395Swnj register int unit; 39213Sbill { 39313Sbill register struct tty *tp; 3942479Swnj register struct dhdevice *addr; 3952395Swnj register int lpar; 396300Sbill int s; 39713Sbill 3982395Swnj tp = &dh11[unit]; 3992479Swnj addr = (struct dhdevice *)tp->t_addr; 4002468Swnj /* 4012468Swnj * Block interrupts so parameters will be set 4022468Swnj * before the line interrupts. 4032468Swnj */ 404300Sbill s = spl5(); 4052468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 40613Sbill if ((tp->t_ispeed)==0) { 4075406Swnj tp->t_state |= TS_HUPCLS; 4082479Swnj dmctl(unit, DML_OFF, DMSET); 40928147Skarels splx(s); 41013Sbill return; 41113Sbill } 4122395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4132468Swnj if ((tp->t_ispeed) == B134) 4142395Swnj lpar |= BITS6|PENABLE|HDUPLX; 41524269Slepreau else if (tp->t_flags & (RAW|LITOUT|PASS8)) 4162395Swnj lpar |= BITS8; 41713Sbill else 4182395Swnj lpar |= BITS7|PENABLE; 41913Sbill if ((tp->t_flags&EVENP) == 0) 4202395Swnj lpar |= OPAR; 4212468Swnj if ((tp->t_ospeed) == B110) 4222395Swnj lpar |= TWOSB; 4232395Swnj addr->dhlpr = lpar; 424300Sbill splx(s); 42513Sbill } 42613Sbill 42713Sbill /* 42813Sbill * DH11 transmitter interrupt. 42913Sbill * Restart each line which used to be active but has 43013Sbill * terminated transmission since the last interrupt. 43113Sbill */ 4322395Swnj dhxint(dh) 4332395Swnj int dh; 43413Sbill { 43513Sbill register struct tty *tp; 4362479Swnj register struct dhdevice *addr; 43713Sbill short ttybit, bar, *sbar; 4382974Swnj register struct uba_device *ui; 4392468Swnj register int unit; 4402605Swnj u_short cntr; 44113Sbill 4422395Swnj ui = dhinfo[dh]; 4432479Swnj addr = (struct dhdevice *)ui->ui_addr; 4442456Swnj if (addr->un.dhcsr & DH_NXM) { 4452456Swnj addr->un.dhcsr |= DH_CNI; 4462924Swnj printf("dh%d: NXM\n", dh); 447105Sbill } 4482395Swnj sbar = &dhsar[dh]; 44913Sbill bar = *sbar & ~addr->dhbar; 4502395Swnj unit = dh * 16; ttybit = 1; 4512468Swnj addr->un.dhcsr &= (short)~DH_TI; 4522468Swnj for (; bar; unit++, ttybit <<= 1) { 4532468Swnj if (bar & ttybit) { 45413Sbill *sbar &= ~ttybit; 45513Sbill bar &= ~ttybit; 4562395Swnj tp = &dh11[unit]; 4575406Swnj tp->t_state &= ~TS_BUSY; 4585406Swnj if (tp->t_state&TS_FLUSH) 4595406Swnj tp->t_state &= ~TS_FLUSH; 460113Sbill else { 4612456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4622468Swnj /* 4632468Swnj * Do arithmetic in a short to make up 4642468Swnj * for lost 16&17 bits. 4652468Swnj */ 4662605Swnj cntr = addr->dhcar - 4672468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4683101Swnj ndflush(&tp->t_outq, (int)cntr); 469113Sbill } 470113Sbill if (tp->t_line) 47113Sbill (*linesw[tp->t_line].l_start)(tp); 472113Sbill else 47313Sbill dhstart(tp); 47413Sbill } 47513Sbill } 47613Sbill } 47713Sbill 47813Sbill /* 47913Sbill * Start (restart) transmission on the given DH11 line. 48013Sbill */ 48113Sbill dhstart(tp) 4822395Swnj register struct tty *tp; 48313Sbill { 4842479Swnj register struct dhdevice *addr; 4852468Swnj register int car, dh, unit, nch; 4862395Swnj int s; 48713Sbill 4882468Swnj unit = minor(tp->t_dev); 4892468Swnj dh = unit >> 4; 4902468Swnj unit &= 0xf; 4912479Swnj addr = (struct dhdevice *)tp->t_addr; 4922468Swnj 49313Sbill /* 4942468Swnj * Must hold interrupts in following code to prevent 4952468Swnj * state of the tp from changing. 49613Sbill */ 49713Sbill s = spl5(); 4982468Swnj /* 4992468Swnj * If it's currently active, or delaying, no need to do anything. 5002468Swnj */ 5015406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 50213Sbill goto out; 5032468Swnj /* 5042468Swnj * If there are sleepers, and output has drained below low 5052468Swnj * water mark, wake up the sleepers. 5062468Swnj */ 5075406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5085406Swnj if (tp->t_state&TS_ASLEEP) { 5095406Swnj tp->t_state &= ~TS_ASLEEP; 5105406Swnj wakeup((caddr_t)&tp->t_outq); 5115406Swnj } 5125406Swnj if (tp->t_wsel) { 5135406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5145406Swnj tp->t_wsel = 0; 5155406Swnj tp->t_state &= ~TS_WCOLL; 5165406Swnj } 51713Sbill } 5182468Swnj /* 5192468Swnj * Now restart transmission unless the output queue is 5202468Swnj * empty. 5212468Swnj */ 52213Sbill if (tp->t_outq.c_cc == 0) 52313Sbill goto out; 5249549Ssam if (tp->t_flags & (RAW|LITOUT)) 52513Sbill nch = ndqb(&tp->t_outq, 0); 5262395Swnj else { 52713Sbill nch = ndqb(&tp->t_outq, 0200); 5282468Swnj /* 5292468Swnj * If first thing on queue is a delay process it. 5302468Swnj */ 53113Sbill if (nch == 0) { 53213Sbill nch = getc(&tp->t_outq); 5332468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5345406Swnj tp->t_state |= TS_TIMEOUT; 53513Sbill goto out; 53613Sbill } 53713Sbill } 5382468Swnj /* 5392468Swnj * If characters to transmit, restart transmission. 5402468Swnj */ 54113Sbill if (nch) { 5422468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5432468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5443586Sroot /* 5453586Sroot * The following nonsense with short word 5463586Sroot * is to make sure the dhbar |= word below 5473586Sroot * is done with an interlocking bisw2 instruction. 5483586Sroot */ 5493586Sroot { short word = 1 << unit; 5503586Sroot dhsar[dh] |= word; 5512468Swnj addr->dhcar = car; 55213Sbill addr->dhbcr = -nch; 5533586Sroot addr->dhbar |= word; 5543586Sroot } 5555406Swnj tp->t_state |= TS_BUSY; 55613Sbill } 5572395Swnj out: 55813Sbill splx(s); 55913Sbill } 56013Sbill 56113Sbill /* 5622468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 56313Sbill */ 56413Sbill /*ARGSUSED*/ 56513Sbill dhstop(tp, flag) 5662468Swnj register struct tty *tp; 56713Sbill { 5682479Swnj register struct dhdevice *addr; 5692395Swnj register int unit, s; 57013Sbill 5712479Swnj addr = (struct dhdevice *)tp->t_addr; 5722468Swnj /* 5732468Swnj * Block input/output interrupts while messing with state. 5742468Swnj */ 5752468Swnj s = spl5(); 5765406Swnj if (tp->t_state & TS_BUSY) { 5772468Swnj /* 5782468Swnj * Device is transmitting; stop output 5792468Swnj * by selecting the line and setting the byte 5802468Swnj * count to -1. We will clean up later 5812468Swnj * by examining the address where the dh stopped. 5822468Swnj */ 5832395Swnj unit = minor(tp->t_dev); 5842456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5855406Swnj if ((tp->t_state&TS_TTSTOP)==0) 5865406Swnj tp->t_state |= TS_FLUSH; 587113Sbill addr->dhbcr = -1; 588113Sbill } 58913Sbill splx(s); 59013Sbill } 59113Sbill 592168Sbill /* 593280Sbill * Reset state of driver if UBA reset was necessary. 594280Sbill * Reset the csrl and lpr registers on open lines, and 595280Sbill * restart transmitters. 596280Sbill */ 5972395Swnj dhreset(uban) 5982468Swnj int uban; 599280Sbill { 6002395Swnj register int dh, unit; 601280Sbill register struct tty *tp; 6022974Swnj register struct uba_device *ui; 6032421Skre int i; 604280Sbill 6052395Swnj dh = 0; 6062643Swnj for (dh = 0; dh < NDH; dh++) { 6072421Skre ui = dhinfo[dh]; 6082421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6092421Skre continue; 6102924Swnj printf(" dh%d", dh); 61130322Skarels if (dh_uballoc[uban] == dh) { 61230322Skarels int info; 61330322Skarels 61430322Skarels info = uballoc(uban, (caddr_t)cfree, 61530322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 61630322Skarels if (info) 61730322Skarels cbase[uban] = UBAI_ADDR(info); 61830322Skarels else { 61930322Skarels printf(" [can't get uba map]"); 62030322Skarels cbase[uban] = -1; 62130322Skarels } 62225433Skarels } 6232479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 62416190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; 6252421Skre unit = dh * 16; 6262421Skre for (i = 0; i < 16; i++) { 6272421Skre tp = &dh11[unit]; 6285406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6292421Skre dhparam(unit); 6302479Swnj dmctl(unit, DML_ON, DMSET); 6315406Swnj tp->t_state &= ~TS_BUSY; 6322421Skre dhstart(tp); 6332421Skre } 6342421Skre unit++; 635300Sbill } 636300Sbill } 63716190Skarels dhsilos = 0; 638280Sbill } 6392395Swnj 64016190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 6412468Swnj /* 64216190Skarels * At software clock interrupt time, check status. 64316190Skarels * Empty all the dh silos that are in use, and decide whether 64416190Skarels * to turn any silos off or on. 6452468Swnj */ 6462456Swnj dhtimer() 6472456Swnj { 64816190Skarels register int dh, s; 64916190Skarels static int timercalls; 6502456Swnj 65116190Skarels if (dhsilos) { 65216190Skarels dhfasttimers++; /*DEBUG*/ 65316190Skarels timercalls++; 65416190Skarels s = spl5(); 65516190Skarels for (dh = 0; dh < NDH; dh++) 65616190Skarels if (dhsilos & (1 << dh)) 65716190Skarels dhrint(dh); 65816190Skarels splx(s); 65916190Skarels } 66016190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 66116190Skarels dhslowtimers++; /*DEBUG*/ 66216190Skarels timercalls = 0; 66316190Skarels for (dh = 0; dh < NDH; dh++) { 66416190Skarels ave(dhrate[dh], dhchars[dh], 8); 66516190Skarels if ((dhchars[dh] > dhhighrate) && 66616190Skarels ((dhsilos & (1 << dh)) == 0)) { 66716190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 66816190Skarels (dhchars[dh] > 500? 32 : 16); 66916190Skarels dhsilos |= (1 << dh); 67016190Skarels dhtransitions++; /*DEBUG*/ 67116190Skarels } else if ((dhsilos & (1 << dh)) && 67216190Skarels (dhrate[dh] < dhlowrate)) { 67316190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; 67416190Skarels dhsilos &= ~(1 << dh); 67516190Skarels } 67616190Skarels dhchars[dh] = 0; 67716190Skarels } 67816190Skarels } 67916190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); 6802456Swnj } 6812456Swnj 6822468Swnj /* 6832479Swnj * Turn on the line associated with dh dev. 6842468Swnj */ 6852468Swnj dmopen(dev) 6862468Swnj dev_t dev; 6872468Swnj { 6882468Swnj register struct tty *tp; 6892468Swnj register struct dmdevice *addr; 6902974Swnj register struct uba_device *ui; 6912468Swnj register int unit; 6922468Swnj register int dm; 6933792Swnj int s; 6942468Swnj 6952468Swnj unit = minor(dev); 6962479Swnj dm = unit >> 4; 6972468Swnj tp = &dh11[unit]; 6982566Swnj unit &= 0xf; 69916942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 7005406Swnj tp->t_state |= TS_CARR_ON; 7012468Swnj return; 7022468Swnj } 7032468Swnj addr = (struct dmdevice *)ui->ui_addr; 7043792Swnj s = spl5(); 70530341Skarels for (;;) { 70630341Skarels addr->dmcsr &= ~DM_SE; 70730341Skarels while (addr->dmcsr & DM_BUSY) 70830341Skarels ; 70930341Skarels addr->dmcsr = unit; 71030341Skarels addr->dmlstat = DML_ON; 711*30349Skarels if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit))) 71230341Skarels tp->t_state |= TS_CARR_ON; 71330341Skarels addr->dmcsr = DM_IE|DM_SE; 71430341Skarels if (tp->t_state & TS_CARR_ON) 71530341Skarels break; 7162468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 71730341Skarels } 7183792Swnj splx(s); 7192468Swnj } 7202468Swnj 7212468Swnj /* 7222468Swnj * Dump control bits into the DM registers. 7232468Swnj */ 7242468Swnj dmctl(dev, bits, how) 7252468Swnj dev_t dev; 7262468Swnj int bits, how; 7272468Swnj { 7282974Swnj register struct uba_device *ui; 7292468Swnj register struct dmdevice *addr; 7302468Swnj register int unit, s; 7312468Swnj int dm; 7322468Swnj 7332468Swnj unit = minor(dev); 7342468Swnj dm = unit >> 4; 7352468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7362468Swnj return; 7372468Swnj addr = (struct dmdevice *)ui->ui_addr; 7382468Swnj s = spl5(); 7392479Swnj addr->dmcsr &= ~DM_SE; 7402479Swnj while (addr->dmcsr & DM_BUSY) 7412468Swnj ; 7422468Swnj addr->dmcsr = unit & 0xf; 7432468Swnj switch(how) { 7442468Swnj case DMSET: 7452468Swnj addr->dmlstat = bits; 7462468Swnj break; 7472468Swnj case DMBIS: 7482468Swnj addr->dmlstat |= bits; 7492468Swnj break; 7502468Swnj case DMBIC: 7512468Swnj addr->dmlstat &= ~bits; 7522468Swnj break; 7532468Swnj } 7543792Swnj addr->dmcsr = DM_IE|DM_SE; 7552468Swnj splx(s); 7562468Swnj } 7572468Swnj 7582468Swnj /* 7592468Swnj * DM11 interrupt; deal with carrier transitions. 7602468Swnj */ 7612468Swnj dmintr(dm) 7622468Swnj register int dm; 7632468Swnj { 7642974Swnj register struct uba_device *ui; 7652468Swnj register struct tty *tp; 7662468Swnj register struct dmdevice *addr; 76716942Skarels int unit; 7682468Swnj 7692468Swnj ui = dminfo[dm]; 7702479Swnj if (ui == 0) 7712479Swnj return; 7722468Swnj addr = (struct dmdevice *)ui->ui_addr; 7733997Sroot if (addr->dmcsr&DM_DONE) { 7743997Sroot if (addr->dmcsr&DM_CF) { 77516942Skarels unit = addr->dmcsr & 0xf; 77616942Skarels tp = &dh11[(dm << 4) + unit]; 77725394Skarels if (addr->dmlstat & DML_CAR) 77825394Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 77925394Skarels else if ((dhsoftCAR[dm] & (1<<unit)) == 0 && 78025394Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 78125394Skarels addr->dmlstat = 0; 7823997Sroot } 7833997Sroot addr->dmcsr = DM_IE|DM_SE; 7842468Swnj } 7852468Swnj } 7862625Swnj #endif 787