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*30322Skarels * @(#)dh.c 7.2 (Berkeley) 12/19/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 /* 85*30322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS. 86*30322Skarels * The identity of the board which allocated resources is recorded, 87*30322Skarels * 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 */ 91*30322Skarels int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */ 92*30322Skarels 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) 1012395Swnj caddr_t reg; 1022395Swnj { 1032468Swnj register int br, cvec; /* these are ``value-result'' */ 1042479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1052395Swnj 1062605Swnj #ifdef lint 1072605Swnj br = 0; cvec = br; br = cvec; 1087384Sroot if (ndh11 == 0) ndh11 = 1; 1094932Swnj dhrint(0); dhxint(0); 1102605Swnj #endif 1112696Swnj #ifndef notdef 1122566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1136380Swnj DELAY(1000); 1147384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1152566Swnj dhaddr->un.dhcsr = 0; 1162566Swnj #else 1172456Swnj dhaddr->un.dhcsr = DH_TIE; 1182456Swnj DELAY(5); 1192456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1202421Skre dhaddr->dhbcr = -1; 1212456Swnj dhaddr->dhcar = 0; 1222421Skre dhaddr->dhbar = 1; 1232456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1242421Skre dhaddr->un.dhcsr = 0; 1252456Swnj if (cvec && cvec != 0x200) 1262456Swnj cvec -= 4; /* transmit -> receive */ 1272482Swnj #endif 1287408Skre return (sizeof (struct dhdevice)); 1292395Swnj } 1302395Swnj 1312456Swnj /* 1322605Swnj * Routine called to attach a dh. 1332456Swnj */ 1342605Swnj dhattach(ui) 1352974Swnj struct uba_device *ui; 1362395Swnj { 1372395Swnj 1382566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 13926219Skarels cbase[ui->ui_ubanum] = -1; 140*30322Skarels dh_uballoc[ui->ui_unit] = -1; 1412395Swnj } 1422395Swnj 14313Sbill /* 1442479Swnj * Configuration routine to cause a dm to interrupt. 1452479Swnj */ 1462605Swnj dmprobe(reg) 1472605Swnj caddr_t reg; 1482479Swnj { 1492479Swnj register int br, vec; /* value-result */ 1502605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1512479Swnj 1522605Swnj #ifdef lint 1533101Swnj br = 0; vec = br; br = vec; 1546185Ssam dmintr(0); 1552605Swnj #endif 1562479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1572479Swnj DELAY(20); 1582479Swnj dmaddr->dmcsr = 0; 1592605Swnj return (1); 1602479Swnj } 1612479Swnj 1622605Swnj /*ARGSUSED*/ 1632605Swnj dmattach(ui) 1642974Swnj struct uba_device *ui; 1652479Swnj { 1662479Swnj 1672479Swnj /* no local state to set up */ 1682479Swnj } 1692479Swnj 1702479Swnj /* 1712468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1722468Swnj * is the first dh on this uba. Turn on this dh if this is 1732468Swnj * the first use of it. Also do a dmopen to wait for carrier. 17413Sbill */ 17513Sbill /*ARGSUSED*/ 17613Sbill dhopen(dev, flag) 1772395Swnj dev_t dev; 17813Sbill { 17913Sbill register struct tty *tp; 1802395Swnj register int unit, dh; 1812479Swnj register struct dhdevice *addr; 1822974Swnj register struct uba_device *ui; 18313Sbill int s; 18413Sbill 1852395Swnj unit = minor(dev); 1862395Swnj dh = unit >> 4; 1878566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 1888566Sroot return (ENXIO); 1892395Swnj tp = &dh11[unit]; 1908566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1918566Sroot return (EBUSY); 1922479Swnj addr = (struct dhdevice *)ui->ui_addr; 19313Sbill tp->t_addr = (caddr_t)addr; 19413Sbill tp->t_oproc = dhstart; 1955406Swnj tp->t_state |= TS_WOPEN; 1962468Swnj /* 1972468Swnj * While setting up state for this uba and this dh, 1982468Swnj * block uba resets which can clear the state. 1992468Swnj */ 2002468Swnj s = spl5(); 20126219Skarels if (cbase[ui->ui_ubanum] == -1) { 202*30322Skarels dh_uballoc[ui->ui_ubanum] = dh; 203*30322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, 204*30322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); 20513Sbill } 20616190Skarels if (timerstarted == 0) { 20716190Skarels timerstarted++; 20816190Skarels timeout(dhtimer, (caddr_t) 0, hz); 20916190Skarels } 2102456Swnj if ((dhact&(1<<dh)) == 0) { 2112456Swnj addr->un.dhcsr |= DH_IE; 2122468Swnj dhact |= (1<<dh); 21316190Skarels addr->dhsilo = 0; 2142456Swnj } 21513Sbill splx(s); 2162468Swnj /* 21727049Skarels * If this is first open, initialize tty state to default. 2182468Swnj */ 2195406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 22013Sbill ttychars(tp); 22127049Skarels #ifndef PORTSELECTOR 22227049Skarels if (tp->t_ispeed == 0) { 22327049Skarels #else 22427049Skarels tp->t_state |= TS_HUPCLS; 22527049Skarels #endif PORTSELECTOR 22627049Skarels tp->t_ispeed = ISPEED; 22727049Skarels tp->t_ospeed = ISPEED; 22827049Skarels tp->t_flags = IFLAGS; 22927049Skarels #ifndef PORTSELECTOR 23027049Skarels } 23127049Skarels #endif PORTSELECTOR 2322395Swnj dhparam(unit); 23313Sbill } 2342468Swnj /* 2352468Swnj * Wait for carrier, then process line discipline specific open. 2362468Swnj */ 23713Sbill dmopen(dev); 2388566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 23913Sbill } 24013Sbill 24113Sbill /* 2422468Swnj * Close a DH11 line, turning off the DM11. 24313Sbill */ 24413Sbill /*ARGSUSED*/ 24513Sbill dhclose(dev, flag) 2462395Swnj dev_t dev; 2472395Swnj int flag; 24813Sbill { 24913Sbill register struct tty *tp; 2502395Swnj register unit; 25113Sbill 2522395Swnj unit = minor(dev); 2532395Swnj tp = &dh11[unit]; 25413Sbill (*linesw[tp->t_line].l_close)(tp); 2552479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2565406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2572479Swnj dmctl(unit, DML_OFF, DMSET); 25813Sbill ttyclose(tp); 25913Sbill } 26013Sbill 2617725Sroot dhread(dev, uio) 2622395Swnj dev_t dev; 2637725Sroot struct uio *uio; 26413Sbill { 2658490Sroot register struct tty *tp = &dh11[minor(dev)]; 26613Sbill 2677725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 26813Sbill } 26913Sbill 2707831Sroot dhwrite(dev, uio) 2712395Swnj dev_t dev; 2727831Sroot struct uio *uio; 27313Sbill { 2748490Sroot register struct tty *tp = &dh11[minor(dev)]; 27513Sbill 2768490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 27713Sbill } 27813Sbill 27913Sbill /* 28013Sbill * DH11 receiver interrupt. 28113Sbill */ 2822395Swnj dhrint(dh) 2832395Swnj int dh; 28413Sbill { 28513Sbill register struct tty *tp; 2862395Swnj register c; 2872479Swnj register struct dhdevice *addr; 288117Sbill register struct tty *tp0; 2892974Swnj register struct uba_device *ui; 2902924Swnj int overrun = 0; 29113Sbill 2922395Swnj ui = dhinfo[dh]; 2932479Swnj if (ui == 0 || ui->ui_alive == 0) 2942479Swnj return; 2952479Swnj addr = (struct dhdevice *)ui->ui_addr; 2962468Swnj tp0 = &dh11[dh<<4]; 2972468Swnj /* 2982468Swnj * Loop fetching characters from the silo for this 2992468Swnj * dh until there are no more in the silo. 3002468Swnj */ 3012468Swnj while ((c = addr->dhrcr) < 0) { 3022468Swnj tp = tp0 + ((c>>8)&0xf); 30316190Skarels dhchars[dh]++; 3045406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 30525394Skarels wakeup((caddr_t)&tp->t_rawq); 30625394Skarels #ifdef PORTSELECTOR 30725394Skarels if ((tp->t_state&TS_WOPEN) == 0) 3086615Ssam #endif 30925394Skarels continue; 31013Sbill } 3112468Swnj if (c & DH_PE) 31213Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 31313Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 31413Sbill continue; 3152924Swnj if ((c & DH_DO) && overrun == 0) { 31624840Seric log(LOG_WARNING, "dh%d: silo overflow\n", dh); 3172924Swnj overrun = 1; 3182924Swnj } 3192468Swnj if (c & DH_FE) 3202468Swnj /* 3212468Swnj * At framing error (break) generate 3222468Swnj * a null (in raw mode, for getty), or a 3232468Swnj * interrupt (in cooked/cbreak mode). 3242468Swnj */ 32513Sbill if (tp->t_flags&RAW) 3262468Swnj c = 0; 32713Sbill else 3289549Ssam c = tp->t_intrc; 3292730Swnj #if NBK > 0 330139Sbill if (tp->t_line == NETLDISC) { 331117Sbill c &= 0177; 332168Sbill BKINPUT(c, tp); 333117Sbill } else 3342730Swnj #endif 3352468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 33613Sbill } 33713Sbill } 33813Sbill 33913Sbill /* 3402468Swnj * Ioctl for DH11. 34113Sbill */ 34213Sbill /*ARGSUSED*/ 3437629Ssam dhioctl(dev, cmd, data, flag) 3447629Ssam caddr_t data; 34513Sbill { 34613Sbill register struct tty *tp; 3478566Sroot register int unit = minor(dev); 3488566Sroot int error; 34913Sbill 3502395Swnj tp = &dh11[unit]; 3518566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3528566Sroot if (error >= 0) 3538566Sroot return (error); 3548566Sroot error = ttioctl(tp, cmd, data, flag); 3558566Sroot if (error >= 0) { 35617561Sbloom if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 35717561Sbloom cmd == TIOCLBIC || cmd == TIOCLSET) 3582395Swnj dhparam(unit); 3598566Sroot return (error); 3608566Sroot } 3618566Sroot switch (cmd) { 3627629Ssam 363168Sbill case TIOCSBRK: 3642479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 365168Sbill break; 3667629Ssam 367168Sbill case TIOCCBRK: 3682479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 369168Sbill break; 3707629Ssam 371168Sbill case TIOCSDTR: 3722479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 373168Sbill break; 3747629Ssam 375168Sbill case TIOCCDTR: 3762479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 377168Sbill break; 3787629Ssam 379168Sbill default: 3808566Sroot return (ENOTTY); 381168Sbill } 3828566Sroot return (0); 38313Sbill } 38413Sbill 38513Sbill /* 38613Sbill * Set parameters from open or stty into the DH hardware 38713Sbill * registers. 38813Sbill */ 3892395Swnj dhparam(unit) 3902395Swnj register int unit; 39113Sbill { 39213Sbill register struct tty *tp; 3932479Swnj register struct dhdevice *addr; 3942395Swnj register int lpar; 395300Sbill int s; 39613Sbill 3972395Swnj tp = &dh11[unit]; 3982479Swnj addr = (struct dhdevice *)tp->t_addr; 3992468Swnj /* 4002468Swnj * Block interrupts so parameters will be set 4012468Swnj * before the line interrupts. 4022468Swnj */ 403300Sbill s = spl5(); 4042468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 40513Sbill if ((tp->t_ispeed)==0) { 4065406Swnj tp->t_state |= TS_HUPCLS; 4072479Swnj dmctl(unit, DML_OFF, DMSET); 40828147Skarels splx(s); 40913Sbill return; 41013Sbill } 4112395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4122468Swnj if ((tp->t_ispeed) == B134) 4132395Swnj lpar |= BITS6|PENABLE|HDUPLX; 41424269Slepreau else if (tp->t_flags & (RAW|LITOUT|PASS8)) 4152395Swnj lpar |= BITS8; 41613Sbill else 4172395Swnj lpar |= BITS7|PENABLE; 41813Sbill if ((tp->t_flags&EVENP) == 0) 4192395Swnj lpar |= OPAR; 4202468Swnj if ((tp->t_ospeed) == B110) 4212395Swnj lpar |= TWOSB; 4222395Swnj addr->dhlpr = lpar; 423300Sbill splx(s); 42413Sbill } 42513Sbill 42613Sbill /* 42713Sbill * DH11 transmitter interrupt. 42813Sbill * Restart each line which used to be active but has 42913Sbill * terminated transmission since the last interrupt. 43013Sbill */ 4312395Swnj dhxint(dh) 4322395Swnj int dh; 43313Sbill { 43413Sbill register struct tty *tp; 4352479Swnj register struct dhdevice *addr; 43613Sbill short ttybit, bar, *sbar; 4372974Swnj register struct uba_device *ui; 4382468Swnj register int unit; 4392605Swnj u_short cntr; 44013Sbill 4412395Swnj ui = dhinfo[dh]; 4422479Swnj addr = (struct dhdevice *)ui->ui_addr; 4432456Swnj if (addr->un.dhcsr & DH_NXM) { 4442456Swnj addr->un.dhcsr |= DH_CNI; 4452924Swnj printf("dh%d: NXM\n", dh); 446105Sbill } 4472395Swnj sbar = &dhsar[dh]; 44813Sbill bar = *sbar & ~addr->dhbar; 4492395Swnj unit = dh * 16; ttybit = 1; 4502468Swnj addr->un.dhcsr &= (short)~DH_TI; 4512468Swnj for (; bar; unit++, ttybit <<= 1) { 4522468Swnj if (bar & ttybit) { 45313Sbill *sbar &= ~ttybit; 45413Sbill bar &= ~ttybit; 4552395Swnj tp = &dh11[unit]; 4565406Swnj tp->t_state &= ~TS_BUSY; 4575406Swnj if (tp->t_state&TS_FLUSH) 4585406Swnj tp->t_state &= ~TS_FLUSH; 459113Sbill else { 4602456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4612468Swnj /* 4622468Swnj * Do arithmetic in a short to make up 4632468Swnj * for lost 16&17 bits. 4642468Swnj */ 4652605Swnj cntr = addr->dhcar - 4662468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4673101Swnj ndflush(&tp->t_outq, (int)cntr); 468113Sbill } 469113Sbill if (tp->t_line) 47013Sbill (*linesw[tp->t_line].l_start)(tp); 471113Sbill else 47213Sbill dhstart(tp); 47313Sbill } 47413Sbill } 47513Sbill } 47613Sbill 47713Sbill /* 47813Sbill * Start (restart) transmission on the given DH11 line. 47913Sbill */ 48013Sbill dhstart(tp) 4812395Swnj register struct tty *tp; 48213Sbill { 4832479Swnj register struct dhdevice *addr; 4842468Swnj register int car, dh, unit, nch; 4852395Swnj int s; 48613Sbill 4872468Swnj unit = minor(tp->t_dev); 4882468Swnj dh = unit >> 4; 4892468Swnj unit &= 0xf; 4902479Swnj addr = (struct dhdevice *)tp->t_addr; 4912468Swnj 49213Sbill /* 4932468Swnj * Must hold interrupts in following code to prevent 4942468Swnj * state of the tp from changing. 49513Sbill */ 49613Sbill s = spl5(); 4972468Swnj /* 4982468Swnj * If it's currently active, or delaying, no need to do anything. 4992468Swnj */ 5005406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 50113Sbill goto out; 5022468Swnj /* 5032468Swnj * If there are sleepers, and output has drained below low 5042468Swnj * water mark, wake up the sleepers. 5052468Swnj */ 5065406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5075406Swnj if (tp->t_state&TS_ASLEEP) { 5085406Swnj tp->t_state &= ~TS_ASLEEP; 5095406Swnj wakeup((caddr_t)&tp->t_outq); 5105406Swnj } 5115406Swnj if (tp->t_wsel) { 5125406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5135406Swnj tp->t_wsel = 0; 5145406Swnj tp->t_state &= ~TS_WCOLL; 5155406Swnj } 51613Sbill } 5172468Swnj /* 5182468Swnj * Now restart transmission unless the output queue is 5192468Swnj * empty. 5202468Swnj */ 52113Sbill if (tp->t_outq.c_cc == 0) 52213Sbill goto out; 5239549Ssam if (tp->t_flags & (RAW|LITOUT)) 52413Sbill nch = ndqb(&tp->t_outq, 0); 5252395Swnj else { 52613Sbill nch = ndqb(&tp->t_outq, 0200); 5272468Swnj /* 5282468Swnj * If first thing on queue is a delay process it. 5292468Swnj */ 53013Sbill if (nch == 0) { 53113Sbill nch = getc(&tp->t_outq); 5322468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5335406Swnj tp->t_state |= TS_TIMEOUT; 53413Sbill goto out; 53513Sbill } 53613Sbill } 5372468Swnj /* 5382468Swnj * If characters to transmit, restart transmission. 5392468Swnj */ 54013Sbill if (nch) { 5412468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5422468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5433586Sroot /* 5443586Sroot * The following nonsense with short word 5453586Sroot * is to make sure the dhbar |= word below 5463586Sroot * is done with an interlocking bisw2 instruction. 5473586Sroot */ 5483586Sroot { short word = 1 << unit; 5493586Sroot dhsar[dh] |= word; 5502468Swnj addr->dhcar = car; 55113Sbill addr->dhbcr = -nch; 5523586Sroot addr->dhbar |= word; 5533586Sroot } 5545406Swnj tp->t_state |= TS_BUSY; 55513Sbill } 5562395Swnj out: 55713Sbill splx(s); 55813Sbill } 55913Sbill 56013Sbill /* 5612468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 56213Sbill */ 56313Sbill /*ARGSUSED*/ 56413Sbill dhstop(tp, flag) 5652468Swnj register struct tty *tp; 56613Sbill { 5672479Swnj register struct dhdevice *addr; 5682395Swnj register int unit, s; 56913Sbill 5702479Swnj addr = (struct dhdevice *)tp->t_addr; 5712468Swnj /* 5722468Swnj * Block input/output interrupts while messing with state. 5732468Swnj */ 5742468Swnj s = spl5(); 5755406Swnj if (tp->t_state & TS_BUSY) { 5762468Swnj /* 5772468Swnj * Device is transmitting; stop output 5782468Swnj * by selecting the line and setting the byte 5792468Swnj * count to -1. We will clean up later 5802468Swnj * by examining the address where the dh stopped. 5812468Swnj */ 5822395Swnj unit = minor(tp->t_dev); 5832456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5845406Swnj if ((tp->t_state&TS_TTSTOP)==0) 5855406Swnj tp->t_state |= TS_FLUSH; 586113Sbill addr->dhbcr = -1; 587113Sbill } 58813Sbill splx(s); 58913Sbill } 59013Sbill 591168Sbill /* 592280Sbill * Reset state of driver if UBA reset was necessary. 593280Sbill * Reset the csrl and lpr registers on open lines, and 594280Sbill * restart transmitters. 595280Sbill */ 5962395Swnj dhreset(uban) 5972468Swnj int uban; 598280Sbill { 5992395Swnj register int dh, unit; 600280Sbill register struct tty *tp; 6012974Swnj register struct uba_device *ui; 6022421Skre int i; 603280Sbill 6042395Swnj dh = 0; 6052643Swnj for (dh = 0; dh < NDH; dh++) { 6062421Skre ui = dhinfo[dh]; 6072421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6082421Skre continue; 6092924Swnj printf(" dh%d", dh); 610*30322Skarels if (dh_uballoc[uban] == dh) { 611*30322Skarels int info; 612*30322Skarels 613*30322Skarels info = uballoc(uban, (caddr_t)cfree, 614*30322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 615*30322Skarels if (info) 616*30322Skarels cbase[uban] = UBAI_ADDR(info); 617*30322Skarels else { 618*30322Skarels printf(" [can't get uba map]"); 619*30322Skarels cbase[uban] = -1; 620*30322Skarels } 62125433Skarels } 6222479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 62316190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; 6242421Skre unit = dh * 16; 6252421Skre for (i = 0; i < 16; i++) { 6262421Skre tp = &dh11[unit]; 6275406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6282421Skre dhparam(unit); 6292479Swnj dmctl(unit, DML_ON, DMSET); 6305406Swnj tp->t_state &= ~TS_BUSY; 6312421Skre dhstart(tp); 6322421Skre } 6332421Skre unit++; 634300Sbill } 635300Sbill } 63616190Skarels dhsilos = 0; 637280Sbill } 6382395Swnj 63916190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 6402468Swnj /* 64116190Skarels * At software clock interrupt time, check status. 64216190Skarels * Empty all the dh silos that are in use, and decide whether 64316190Skarels * to turn any silos off or on. 6442468Swnj */ 6452456Swnj dhtimer() 6462456Swnj { 64716190Skarels register int dh, s; 64816190Skarels static int timercalls; 6492456Swnj 65016190Skarels if (dhsilos) { 65116190Skarels dhfasttimers++; /*DEBUG*/ 65216190Skarels timercalls++; 65316190Skarels s = spl5(); 65416190Skarels for (dh = 0; dh < NDH; dh++) 65516190Skarels if (dhsilos & (1 << dh)) 65616190Skarels dhrint(dh); 65716190Skarels splx(s); 65816190Skarels } 65916190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 66016190Skarels dhslowtimers++; /*DEBUG*/ 66116190Skarels timercalls = 0; 66216190Skarels for (dh = 0; dh < NDH; dh++) { 66316190Skarels ave(dhrate[dh], dhchars[dh], 8); 66416190Skarels if ((dhchars[dh] > dhhighrate) && 66516190Skarels ((dhsilos & (1 << dh)) == 0)) { 66616190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 66716190Skarels (dhchars[dh] > 500? 32 : 16); 66816190Skarels dhsilos |= (1 << dh); 66916190Skarels dhtransitions++; /*DEBUG*/ 67016190Skarels } else if ((dhsilos & (1 << dh)) && 67116190Skarels (dhrate[dh] < dhlowrate)) { 67216190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; 67316190Skarels dhsilos &= ~(1 << dh); 67416190Skarels } 67516190Skarels dhchars[dh] = 0; 67616190Skarels } 67716190Skarels } 67816190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); 6792456Swnj } 6802456Swnj 6812468Swnj /* 6822479Swnj * Turn on the line associated with dh dev. 6832468Swnj */ 6842468Swnj dmopen(dev) 6852468Swnj dev_t dev; 6862468Swnj { 6872468Swnj register struct tty *tp; 6882468Swnj register struct dmdevice *addr; 6892974Swnj register struct uba_device *ui; 6902468Swnj register int unit; 6912468Swnj register int dm; 6923792Swnj int s; 6932468Swnj 6942468Swnj unit = minor(dev); 6952479Swnj dm = unit >> 4; 6962468Swnj tp = &dh11[unit]; 6972566Swnj unit &= 0xf; 69816942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 6995406Swnj tp->t_state |= TS_CARR_ON; 7002468Swnj return; 7012468Swnj } 7022468Swnj addr = (struct dmdevice *)ui->ui_addr; 7033792Swnj s = spl5(); 7042479Swnj addr->dmcsr &= ~DM_SE; 7052479Swnj while (addr->dmcsr & DM_BUSY) 7062468Swnj ; 7072566Swnj addr->dmcsr = unit; 7082479Swnj addr->dmlstat = DML_ON; 70916942Skarels if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit))) 7105406Swnj tp->t_state |= TS_CARR_ON; 7113792Swnj addr->dmcsr = DM_IE|DM_SE; 7125406Swnj while ((tp->t_state&TS_CARR_ON)==0) 7132468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7143792Swnj splx(s); 7152468Swnj } 7162468Swnj 7172468Swnj /* 7182468Swnj * Dump control bits into the DM registers. 7192468Swnj */ 7202468Swnj dmctl(dev, bits, how) 7212468Swnj dev_t dev; 7222468Swnj int bits, how; 7232468Swnj { 7242974Swnj register struct uba_device *ui; 7252468Swnj register struct dmdevice *addr; 7262468Swnj register int unit, s; 7272468Swnj int dm; 7282468Swnj 7292468Swnj unit = minor(dev); 7302468Swnj dm = unit >> 4; 7312468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7322468Swnj return; 7332468Swnj addr = (struct dmdevice *)ui->ui_addr; 7342468Swnj s = spl5(); 7352479Swnj addr->dmcsr &= ~DM_SE; 7362479Swnj while (addr->dmcsr & DM_BUSY) 7372468Swnj ; 7382468Swnj addr->dmcsr = unit & 0xf; 7392468Swnj switch(how) { 7402468Swnj case DMSET: 7412468Swnj addr->dmlstat = bits; 7422468Swnj break; 7432468Swnj case DMBIS: 7442468Swnj addr->dmlstat |= bits; 7452468Swnj break; 7462468Swnj case DMBIC: 7472468Swnj addr->dmlstat &= ~bits; 7482468Swnj break; 7492468Swnj } 7503792Swnj addr->dmcsr = DM_IE|DM_SE; 7512468Swnj splx(s); 7522468Swnj } 7532468Swnj 7542468Swnj /* 7552468Swnj * DM11 interrupt; deal with carrier transitions. 7562468Swnj */ 7572468Swnj dmintr(dm) 7582468Swnj register int dm; 7592468Swnj { 7602974Swnj register struct uba_device *ui; 7612468Swnj register struct tty *tp; 7622468Swnj register struct dmdevice *addr; 76316942Skarels int unit; 7642468Swnj 7652468Swnj ui = dminfo[dm]; 7662479Swnj if (ui == 0) 7672479Swnj return; 7682468Swnj addr = (struct dmdevice *)ui->ui_addr; 7693997Sroot if (addr->dmcsr&DM_DONE) { 7703997Sroot if (addr->dmcsr&DM_CF) { 77116942Skarels unit = addr->dmcsr & 0xf; 77216942Skarels tp = &dh11[(dm << 4) + unit]; 77325394Skarels if (addr->dmlstat & DML_CAR) 77425394Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 77525394Skarels else if ((dhsoftCAR[dm] & (1<<unit)) == 0 && 77625394Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 77725394Skarels addr->dmlstat = 0; 7783997Sroot } 7793997Sroot addr->dmcsr = DM_IE|DM_SE; 7802468Swnj } 7812468Swnj } 7822625Swnj #endif 783