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*40729Skarels * @(#)dh.c 7.11 (Berkeley) 04/03/90 723320Smckusick */ 813Sbill 91934Swnj #include "dh.h" 102643Swnj #if NDH > 0 1113Sbill /* 122479Swnj * DH-11/DM-11 driver 1313Sbill */ 1437511Smckusick #include "machine/pte.h" 159771Ssam 162730Swnj #include "bk.h" 1716062Skarels #include "uba.h" 1817122Sbloom #include "param.h" 1917122Sbloom #include "conf.h" 2017122Sbloom #include "user.h" 2117122Sbloom #include "proc.h" 2217122Sbloom #include "ioctl.h" 2317122Sbloom #include "tty.h" 2417122Sbloom #include "map.h" 2517122Sbloom #include "buf.h" 2617122Sbloom #include "vm.h" 2717122Sbloom #include "kernel.h" 2818311Sralph #include "syslog.h" 298472Sroot 3017122Sbloom #include "ubareg.h" 3117122Sbloom #include "ubavar.h" 3217122Sbloom #include "dhreg.h" 3317122Sbloom #include "dmreg.h" 348472Sroot 3517122Sbloom #include "bkmac.h" 3617122Sbloom #include "clist.h" 3717122Sbloom #include "file.h" 3817122Sbloom #include "uio.h" 3913Sbill 402468Swnj /* 412479Swnj * Definition of the driver for the auto-configuration program. 422479Swnj * There is one definition for the dh and one for the dm. 432468Swnj */ 4416190Skarels int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer(); 452974Swnj struct uba_device *dhinfo[NDH]; 462395Swnj u_short dhstd[] = { 0 }; 472395Swnj struct uba_driver dhdriver = 482605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 492395Swnj 502605Swnj int dmprobe(), dmattach(), dmintr(); 512974Swnj struct uba_device *dminfo[NDH]; 522479Swnj u_short dmstd[] = { 0 }; 532479Swnj struct uba_driver dmdriver = 542605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 5513Sbill 566615Ssam #ifndef PORTSELECTOR 5739061Smarc #define ISPEED TTYDEF_SPEED 5839061Smarc #define LFLAG TTYDEF_LFLAG 596615Ssam #else 606615Ssam #define ISPEED B4800 6139061Smarc #define LFLAG (TTYDEF_LFLAG&~ECHO) 626615Ssam #endif 636615Ssam 6416190Skarels #define FASTTIMER (hz/30) /* scan rate with silos on */ 6516190Skarels 6613Sbill /* 672479Swnj * Local variables for the driver 6813Sbill */ 692643Swnj short dhsar[NDH]; /* software copy of last bar */ 702643Swnj short dhsoftCAR[NDH]; 7113Sbill 722643Swnj struct tty dh11[NDH*16]; 732643Swnj int ndh11 = NDH*16; 742479Swnj int dhact; /* mask of active dh's */ 7516190Skarels int dhsilos; /* mask of dh's with silo in use */ 7616190Skarels int dhchars[NDH]; /* recent input count */ 7716190Skarels int dhrate[NDH]; /* smoothed input count */ 7816190Skarels int dhhighrate = 100; /* silo on if dhchars > dhhighrate */ 7916190Skarels int dhlowrate = 75; /* silo off if dhrate < dhlowrate */ 8016190Skarels static short timerstarted; 812479Swnj int dhstart(), ttrstrt(); 8213Sbill 8339061Smarc struct speedtab dhspeedtab[] = { 8439061Smarc 19200, 14, 8539061Smarc 9600, 13, 8639061Smarc 4800, 12, 8739061Smarc 2400, 11, 8839061Smarc 1800, 10, 8939061Smarc 1200, 9, 9039061Smarc 600, 8, 9139061Smarc 300, 7, 9239061Smarc 200, 6, 9339061Smarc 150, 5, 9439061Smarc 134, 4, 9539061Smarc 110, 3, 9639061Smarc 75, 2, 9739061Smarc 50, 1, 9839061Smarc 0, 0, 9939061Smarc EXTA, 14, 10039061Smarc EXTB, 15, 10139061Smarc -1, -1 10239061Smarc }; 10339061Smarc 1042479Swnj /* 10530322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS. 10630322Skarels * The identity of the board which allocated resources is recorded, 10730322Skarels * so the process may be repeated after UNIBUS resets. 1082479Swnj * The UBACVT macro converts a clist space address for unibus uban 1092479Swnj * into an i/o space address for the DMA routine. 1102479Swnj */ 11130322Skarels int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */ 11230322Skarels int cbase[NUBA]; /* base address of clists in unibus map */ 1132479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 11413Sbill 1152456Swnj /* 1162456Swnj * Routine for configuration to force a dh to interrupt. 1172456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1182456Swnj */ 1192468Swnj /*ARGSUSED*/ 1202605Swnj dhprobe(reg) 1212395Swnj caddr_t reg; 1222395Swnj { 1232468Swnj register int br, cvec; /* these are ``value-result'' */ 1242479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1252395Swnj 1262605Swnj #ifdef lint 1272605Swnj br = 0; cvec = br; br = cvec; 1287384Sroot if (ndh11 == 0) ndh11 = 1; 1294932Swnj dhrint(0); dhxint(0); 1302605Swnj #endif 1312696Swnj #ifndef notdef 1322566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1336380Swnj DELAY(1000); 1347384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1352566Swnj dhaddr->un.dhcsr = 0; 1362566Swnj #else 1372456Swnj dhaddr->un.dhcsr = DH_TIE; 1382456Swnj DELAY(5); 1392456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1402421Skre dhaddr->dhbcr = -1; 1412456Swnj dhaddr->dhcar = 0; 1422421Skre dhaddr->dhbar = 1; 1432456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1442421Skre dhaddr->un.dhcsr = 0; 1452456Swnj if (cvec && cvec != 0x200) 1462456Swnj cvec -= 4; /* transmit -> receive */ 1472482Swnj #endif 1487408Skre return (sizeof (struct dhdevice)); 1492395Swnj } 1502395Swnj 1512456Swnj /* 1522605Swnj * Routine called to attach a dh. 1532456Swnj */ 1542605Swnj dhattach(ui) 1552974Swnj struct uba_device *ui; 1562395Swnj { 1572395Swnj 1582566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 15926219Skarels cbase[ui->ui_ubanum] = -1; 16036610Sbostic dh_uballoc[ui->ui_ubanum] = -1; 1612395Swnj } 1622395Swnj 16313Sbill /* 1642479Swnj * Configuration routine to cause a dm to interrupt. 1652479Swnj */ 1662605Swnj dmprobe(reg) 1672605Swnj caddr_t reg; 1682479Swnj { 1692479Swnj register int br, vec; /* value-result */ 1702605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1712479Swnj 1722605Swnj #ifdef lint 1733101Swnj br = 0; vec = br; br = vec; 1746185Ssam dmintr(0); 1752605Swnj #endif 1762479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1772479Swnj DELAY(20); 1782479Swnj dmaddr->dmcsr = 0; 1792605Swnj return (1); 1802479Swnj } 1812479Swnj 1822605Swnj /*ARGSUSED*/ 1832605Swnj dmattach(ui) 1842974Swnj struct uba_device *ui; 1852479Swnj { 1862479Swnj 1872479Swnj /* no local state to set up */ 1882479Swnj } 1892479Swnj 1902479Swnj /* 1912468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1922468Swnj * is the first dh on this uba. Turn on this dh if this is 1932468Swnj * the first use of it. Also do a dmopen to wait for carrier. 19413Sbill */ 19513Sbill /*ARGSUSED*/ 19613Sbill dhopen(dev, flag) 1972395Swnj dev_t dev; 19813Sbill { 19913Sbill register struct tty *tp; 2002395Swnj register int unit, dh; 2012479Swnj register struct dhdevice *addr; 2022974Swnj register struct uba_device *ui; 203*40729Skarels int s, error; 20439061Smarc int dhparam(); 20513Sbill 2062395Swnj unit = minor(dev); 2072395Swnj dh = unit >> 4; 2088566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 2098566Sroot return (ENXIO); 2102395Swnj tp = &dh11[unit]; 2118566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2128566Sroot return (EBUSY); 2132479Swnj addr = (struct dhdevice *)ui->ui_addr; 21413Sbill tp->t_addr = (caddr_t)addr; 21513Sbill tp->t_oproc = dhstart; 21639061Smarc tp->t_param = dhparam; 21739061Smarc tp->t_dev = dev; 2185406Swnj tp->t_state |= TS_WOPEN; 2192468Swnj /* 2202468Swnj * While setting up state for this uba and this dh, 2212468Swnj * block uba resets which can clear the state. 2222468Swnj */ 2232468Swnj s = spl5(); 22426219Skarels if (cbase[ui->ui_ubanum] == -1) { 22530322Skarels dh_uballoc[ui->ui_ubanum] = dh; 22630322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, 22730322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); 22813Sbill } 22916190Skarels if (timerstarted == 0) { 23016190Skarels timerstarted++; 23116190Skarels timeout(dhtimer, (caddr_t) 0, hz); 23216190Skarels } 2332456Swnj if ((dhact&(1<<dh)) == 0) { 2342456Swnj addr->un.dhcsr |= DH_IE; 2352468Swnj dhact |= (1<<dh); 23616190Skarels addr->dhsilo = 0; 2372456Swnj } 23813Sbill splx(s); 2392468Swnj /* 24027049Skarels * If this is first open, initialize tty state to default. 2412468Swnj */ 2425406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 24313Sbill ttychars(tp); 24427049Skarels #ifndef PORTSELECTOR 24527049Skarels if (tp->t_ispeed == 0) { 24639061Smarc #endif 24739061Smarc tp->t_iflag = TTYDEF_IFLAG; 24839061Smarc tp->t_oflag = TTYDEF_OFLAG; 24939061Smarc tp->t_cflag = TTYDEF_CFLAG; 25039061Smarc tp->t_lflag = LFLAG; 25139061Smarc tp->t_ispeed = tp->t_ospeed = ISPEED; 25239061Smarc #ifdef PORTSELECTOR 25339061Smarc tp->t_cflag |= HUPCL; 25427049Skarels #else 25527049Skarels } 25639061Smarc #endif 25739061Smarc dhparam(tp, &tp->t_termios); 25839061Smarc ttsetwater(tp); 25913Sbill } 2602468Swnj /* 2612468Swnj * Wait for carrier, then process line discipline specific open. 2622468Swnj */ 263*40729Skarels if (error = dmopen(dev, flag)) 264*40729Skarels return (error); 2658566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 26613Sbill } 26713Sbill 26813Sbill /* 2692468Swnj * Close a DH11 line, turning off the DM11. 27013Sbill */ 27113Sbill /*ARGSUSED*/ 27213Sbill dhclose(dev, flag) 2732395Swnj dev_t dev; 2742395Swnj int flag; 27513Sbill { 27613Sbill register struct tty *tp; 2772395Swnj register unit; 27813Sbill 2792395Swnj unit = minor(dev); 2802395Swnj tp = &dh11[unit]; 28113Sbill (*linesw[tp->t_line].l_close)(tp); 2822479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 28339061Smarc if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0) 2842479Swnj dmctl(unit, DML_OFF, DMSET); 285*40729Skarels return (ttyclose(tp)); 28613Sbill } 28713Sbill 28839061Smarc dhread(dev, uio, flag) 2892395Swnj dev_t dev; 2907725Sroot struct uio *uio; 29113Sbill { 2928490Sroot register struct tty *tp = &dh11[minor(dev)]; 29313Sbill 29439061Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 29513Sbill } 29613Sbill 29739061Smarc dhwrite(dev, uio, flag) 2982395Swnj dev_t dev; 2997831Sroot struct uio *uio; 30013Sbill { 3018490Sroot register struct tty *tp = &dh11[minor(dev)]; 30213Sbill 30339061Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 30413Sbill } 30513Sbill 30613Sbill /* 30713Sbill * DH11 receiver interrupt. 30813Sbill */ 3092395Swnj dhrint(dh) 3102395Swnj int dh; 31113Sbill { 31213Sbill register struct tty *tp; 31339061Smarc register c, cc; 3142479Swnj register struct dhdevice *addr; 315117Sbill register struct tty *tp0; 3162974Swnj register struct uba_device *ui; 3172924Swnj int overrun = 0; 31813Sbill 3192395Swnj ui = dhinfo[dh]; 3202479Swnj if (ui == 0 || ui->ui_alive == 0) 3212479Swnj return; 3222479Swnj addr = (struct dhdevice *)ui->ui_addr; 3232468Swnj tp0 = &dh11[dh<<4]; 3242468Swnj /* 3252468Swnj * Loop fetching characters from the silo for this 3262468Swnj * dh until there are no more in the silo. 3272468Swnj */ 3282468Swnj while ((c = addr->dhrcr) < 0) { 3292468Swnj tp = tp0 + ((c>>8)&0xf); 33016190Skarels dhchars[dh]++; 3315406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 33225394Skarels wakeup((caddr_t)&tp->t_rawq); 33325394Skarels #ifdef PORTSELECTOR 33425394Skarels if ((tp->t_state&TS_WOPEN) == 0) 3356615Ssam #endif 33625394Skarels continue; 33713Sbill } 33839061Smarc cc = c&0xff; 33939061Smarc if (c&DH_PE) 34039061Smarc cc |= TTY_PE; 34139061Smarc if ((c&DH_DO) && overrun == 0) { 34224840Seric log(LOG_WARNING, "dh%d: silo overflow\n", dh); 3432924Swnj overrun = 1; 3442924Swnj } 34539061Smarc if (c&DH_FE) 34639061Smarc cc |= TTY_FE; 34739061Smarc (*linesw[tp->t_line].l_rint)(cc, tp); 34813Sbill } 34913Sbill } 35013Sbill 35113Sbill /* 3522468Swnj * Ioctl for DH11. 35313Sbill */ 35413Sbill /*ARGSUSED*/ 3557629Ssam dhioctl(dev, cmd, data, flag) 3567629Ssam caddr_t data; 35713Sbill { 35813Sbill register struct tty *tp; 3598566Sroot register int unit = minor(dev); 3608566Sroot int error; 36113Sbill 3622395Swnj tp = &dh11[unit]; 3638566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3648566Sroot if (error >= 0) 3658566Sroot return (error); 3668566Sroot error = ttioctl(tp, cmd, data, flag); 36739061Smarc if (error >= 0) 3688566Sroot return (error); 3698566Sroot switch (cmd) { 3707629Ssam 371168Sbill case TIOCSBRK: 3722479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 373168Sbill break; 3747629Ssam 375168Sbill case TIOCCBRK: 3762479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 377168Sbill break; 3787629Ssam 379168Sbill case TIOCSDTR: 3802479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 381168Sbill break; 3827629Ssam 383168Sbill case TIOCCDTR: 3842479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 385168Sbill break; 3867629Ssam 387168Sbill default: 3888566Sroot return (ENOTTY); 389168Sbill } 3908566Sroot return (0); 39113Sbill } 39213Sbill 39313Sbill /* 39413Sbill * Set parameters from open or stty into the DH hardware 39513Sbill * registers. 39613Sbill */ 39739061Smarc dhparam(tp, t) 39839061Smarc register struct tty *tp; 39939061Smarc register struct termios *t; 40013Sbill { 4012479Swnj register struct dhdevice *addr; 4022395Swnj register int lpar; 40339061Smarc register int cflag = t->c_cflag; 40439061Smarc int unit = minor(tp->t_dev); 405300Sbill int s; 40639061Smarc int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab); 40739061Smarc int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab); 40813Sbill 40939061Smarc /* check requested parameters */ 41039061Smarc if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5) 41139061Smarc return(EINVAL); 41239061Smarc if (ispeed == 0) 41339061Smarc ispeed = ospeed; 41439061Smarc /* and copy to tty */ 41539061Smarc tp->t_ispeed = t->c_ispeed; 41639061Smarc tp->t_ospeed = t->c_ospeed; 41739061Smarc tp->t_cflag = cflag; 4182468Swnj /* 4192468Swnj * Block interrupts so parameters will be set 4202468Swnj * before the line interrupts. 4212468Swnj */ 42239061Smarc addr = (struct dhdevice *)tp->t_addr; 423300Sbill s = spl5(); 4242468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 42539061Smarc if (ospeed == 0) { 42639061Smarc tp->t_cflag |= HUPCL; 4272479Swnj dmctl(unit, DML_OFF, DMSET); 42828147Skarels splx(s); 42939061Smarc return 0; 43013Sbill } 43139061Smarc lpar = (ospeed<<10) | (ispeed<<6); 43239061Smarc switch (cflag&CSIZE) { 43339061Smarc case CS6: lpar |= BITS6; break; 43439061Smarc case CS7: lpar |= BITS7; break; 43539061Smarc case CS8: lpar |= BITS8; break; 43639061Smarc } 43739061Smarc if (cflag&PARENB) 43839061Smarc lpar |= PENABLE; 43939061Smarc if (cflag&PARODD) 4402395Swnj lpar |= OPAR; 44139061Smarc if (cflag&CSTOPB) 4422395Swnj lpar |= TWOSB; 4432395Swnj addr->dhlpr = lpar; 444300Sbill splx(s); 44539061Smarc return 0; 44613Sbill } 44713Sbill 44813Sbill /* 44913Sbill * DH11 transmitter interrupt. 45013Sbill * Restart each line which used to be active but has 45113Sbill * terminated transmission since the last interrupt. 45213Sbill */ 4532395Swnj dhxint(dh) 4542395Swnj int dh; 45513Sbill { 45613Sbill register struct tty *tp; 4572479Swnj register struct dhdevice *addr; 45813Sbill short ttybit, bar, *sbar; 4592974Swnj register struct uba_device *ui; 4602468Swnj register int unit; 4612605Swnj u_short cntr; 46213Sbill 4632395Swnj ui = dhinfo[dh]; 4642479Swnj addr = (struct dhdevice *)ui->ui_addr; 4652456Swnj if (addr->un.dhcsr & DH_NXM) { 4662456Swnj addr->un.dhcsr |= DH_CNI; 4672924Swnj printf("dh%d: NXM\n", dh); 468105Sbill } 4692395Swnj sbar = &dhsar[dh]; 47013Sbill bar = *sbar & ~addr->dhbar; 4712395Swnj unit = dh * 16; ttybit = 1; 4722468Swnj addr->un.dhcsr &= (short)~DH_TI; 4732468Swnj for (; bar; unit++, ttybit <<= 1) { 4742468Swnj if (bar & ttybit) { 47513Sbill *sbar &= ~ttybit; 47613Sbill bar &= ~ttybit; 4772395Swnj tp = &dh11[unit]; 4785406Swnj tp->t_state &= ~TS_BUSY; 4795406Swnj if (tp->t_state&TS_FLUSH) 4805406Swnj tp->t_state &= ~TS_FLUSH; 481113Sbill else { 4822456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4832468Swnj /* 4842468Swnj * Do arithmetic in a short to make up 4852468Swnj * for lost 16&17 bits. 4862468Swnj */ 4872605Swnj cntr = addr->dhcar - 4882468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4893101Swnj ndflush(&tp->t_outq, (int)cntr); 490113Sbill } 491113Sbill if (tp->t_line) 49213Sbill (*linesw[tp->t_line].l_start)(tp); 493113Sbill else 49413Sbill dhstart(tp); 49513Sbill } 49613Sbill } 49713Sbill } 49813Sbill 49913Sbill /* 50013Sbill * Start (restart) transmission on the given DH11 line. 50113Sbill */ 50213Sbill dhstart(tp) 5032395Swnj register struct tty *tp; 50413Sbill { 5052479Swnj register struct dhdevice *addr; 5062468Swnj register int car, dh, unit, nch; 5072395Swnj int s; 50813Sbill 5092468Swnj unit = minor(tp->t_dev); 5102468Swnj dh = unit >> 4; 5112468Swnj unit &= 0xf; 5122479Swnj addr = (struct dhdevice *)tp->t_addr; 5132468Swnj 51413Sbill /* 5152468Swnj * Must hold interrupts in following code to prevent 5162468Swnj * state of the tp from changing. 51713Sbill */ 51813Sbill s = spl5(); 5192468Swnj /* 5202468Swnj * If it's currently active, or delaying, no need to do anything. 5212468Swnj */ 5225406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 52313Sbill goto out; 5242468Swnj /* 5252468Swnj * If there are sleepers, and output has drained below low 5262468Swnj * water mark, wake up the sleepers. 5272468Swnj */ 52839061Smarc if (tp->t_outq.c_cc<=tp->t_lowat) { 5295406Swnj if (tp->t_state&TS_ASLEEP) { 5305406Swnj tp->t_state &= ~TS_ASLEEP; 5315406Swnj wakeup((caddr_t)&tp->t_outq); 5325406Swnj } 5335406Swnj if (tp->t_wsel) { 5345406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5355406Swnj tp->t_wsel = 0; 5365406Swnj tp->t_state &= ~TS_WCOLL; 5375406Swnj } 53813Sbill } 5392468Swnj /* 5402468Swnj * Now restart transmission unless the output queue is 5412468Swnj * empty. 5422468Swnj */ 54313Sbill if (tp->t_outq.c_cc == 0) 54413Sbill goto out; 54539061Smarc if (1 || !(tp->t_oflag&OPOST)) /*XXX*/ 54613Sbill nch = ndqb(&tp->t_outq, 0); 5472395Swnj else { 54813Sbill nch = ndqb(&tp->t_outq, 0200); 5492468Swnj /* 5502468Swnj * If first thing on queue is a delay process it. 5512468Swnj */ 55213Sbill if (nch == 0) { 55313Sbill nch = getc(&tp->t_outq); 5542468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5555406Swnj tp->t_state |= TS_TIMEOUT; 55613Sbill goto out; 55713Sbill } 55813Sbill } 5592468Swnj /* 5602468Swnj * If characters to transmit, restart transmission. 5612468Swnj */ 56213Sbill if (nch) { 5632468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5642468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5653586Sroot /* 5663586Sroot * The following nonsense with short word 5673586Sroot * is to make sure the dhbar |= word below 5683586Sroot * is done with an interlocking bisw2 instruction. 5693586Sroot */ 5703586Sroot { short word = 1 << unit; 5713586Sroot dhsar[dh] |= word; 5722468Swnj addr->dhcar = car; 57313Sbill addr->dhbcr = -nch; 5743586Sroot addr->dhbar |= word; 5753586Sroot } 5765406Swnj tp->t_state |= TS_BUSY; 57713Sbill } 5782395Swnj out: 57913Sbill splx(s); 58013Sbill } 58113Sbill 58213Sbill /* 5832468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 58413Sbill */ 58513Sbill /*ARGSUSED*/ 58613Sbill dhstop(tp, flag) 5872468Swnj register struct tty *tp; 58813Sbill { 5892479Swnj register struct dhdevice *addr; 5902395Swnj register int unit, s; 59113Sbill 5922479Swnj addr = (struct dhdevice *)tp->t_addr; 5932468Swnj /* 5942468Swnj * Block input/output interrupts while messing with state. 5952468Swnj */ 5962468Swnj s = spl5(); 5975406Swnj if (tp->t_state & TS_BUSY) { 5982468Swnj /* 5992468Swnj * Device is transmitting; stop output 6002468Swnj * by selecting the line and setting the byte 6012468Swnj * count to -1. We will clean up later 6022468Swnj * by examining the address where the dh stopped. 6032468Swnj */ 6042395Swnj unit = minor(tp->t_dev); 6052456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6065406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6075406Swnj tp->t_state |= TS_FLUSH; 608113Sbill addr->dhbcr = -1; 609113Sbill } 61013Sbill splx(s); 61113Sbill } 61213Sbill 613168Sbill /* 614280Sbill * Reset state of driver if UBA reset was necessary. 615280Sbill * Reset the csrl and lpr registers on open lines, and 616280Sbill * restart transmitters. 617280Sbill */ 6182395Swnj dhreset(uban) 6192468Swnj int uban; 620280Sbill { 6212395Swnj register int dh, unit; 622280Sbill register struct tty *tp; 6232974Swnj register struct uba_device *ui; 6242421Skre int i; 625280Sbill 6262395Swnj dh = 0; 6272643Swnj for (dh = 0; dh < NDH; dh++) { 6282421Skre ui = dhinfo[dh]; 6292421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6302421Skre continue; 6312924Swnj printf(" dh%d", dh); 63230322Skarels if (dh_uballoc[uban] == dh) { 63330322Skarels int info; 63430322Skarels 63530322Skarels info = uballoc(uban, (caddr_t)cfree, 63630322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 63730322Skarels if (info) 63830322Skarels cbase[uban] = UBAI_ADDR(info); 63930322Skarels else { 64030322Skarels printf(" [can't get uba map]"); 64130322Skarels cbase[uban] = -1; 64230322Skarels } 64325433Skarels } 6442479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 64516190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; 6462421Skre unit = dh * 16; 6472421Skre for (i = 0; i < 16; i++) { 6482421Skre tp = &dh11[unit]; 6495406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6502421Skre dhparam(unit); 6512479Swnj dmctl(unit, DML_ON, DMSET); 6525406Swnj tp->t_state &= ~TS_BUSY; 6532421Skre dhstart(tp); 6542421Skre } 6552421Skre unit++; 656300Sbill } 657300Sbill } 65816190Skarels dhsilos = 0; 659280Sbill } 6602395Swnj 66116190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 6622468Swnj /* 66316190Skarels * At software clock interrupt time, check status. 66416190Skarels * Empty all the dh silos that are in use, and decide whether 66516190Skarels * to turn any silos off or on. 6662468Swnj */ 6672456Swnj dhtimer() 6682456Swnj { 66916190Skarels register int dh, s; 67016190Skarels static int timercalls; 6712456Swnj 67216190Skarels if (dhsilos) { 67316190Skarels dhfasttimers++; /*DEBUG*/ 67416190Skarels timercalls++; 67516190Skarels s = spl5(); 67616190Skarels for (dh = 0; dh < NDH; dh++) 67716190Skarels if (dhsilos & (1 << dh)) 67816190Skarels dhrint(dh); 67916190Skarels splx(s); 68016190Skarels } 68116190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 68216190Skarels dhslowtimers++; /*DEBUG*/ 68316190Skarels timercalls = 0; 68416190Skarels for (dh = 0; dh < NDH; dh++) { 68516190Skarels ave(dhrate[dh], dhchars[dh], 8); 68616190Skarels if ((dhchars[dh] > dhhighrate) && 68716190Skarels ((dhsilos & (1 << dh)) == 0)) { 68816190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 68916190Skarels (dhchars[dh] > 500? 32 : 16); 69016190Skarels dhsilos |= (1 << dh); 69116190Skarels dhtransitions++; /*DEBUG*/ 69216190Skarels } else if ((dhsilos & (1 << dh)) && 69316190Skarels (dhrate[dh] < dhlowrate)) { 69416190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; 69516190Skarels dhsilos &= ~(1 << dh); 69616190Skarels } 69716190Skarels dhchars[dh] = 0; 69816190Skarels } 69916190Skarels } 70016190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); 7012456Swnj } 7022456Swnj 7032468Swnj /* 7042479Swnj * Turn on the line associated with dh dev. 7052468Swnj */ 70639061Smarc dmopen(dev, flag) 7072468Swnj dev_t dev; 7082468Swnj { 7092468Swnj register struct tty *tp; 7102468Swnj register struct dmdevice *addr; 7112974Swnj register struct uba_device *ui; 7122468Swnj register int unit; 7132468Swnj register int dm; 714*40729Skarels int s, error = 0; 7152468Swnj 7162468Swnj unit = minor(dev); 7172479Swnj dm = unit >> 4; 7182468Swnj tp = &dh11[unit]; 7192566Swnj unit &= 0xf; 72016942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 7215406Swnj tp->t_state |= TS_CARR_ON; 722*40729Skarels return (0); 7232468Swnj } 7242468Swnj addr = (struct dmdevice *)ui->ui_addr; 7253792Swnj s = spl5(); 72630341Skarels for (;;) { 72730341Skarels addr->dmcsr &= ~DM_SE; 72830341Skarels while (addr->dmcsr & DM_BUSY) 72930341Skarels ; 73030341Skarels addr->dmcsr = unit; 73130341Skarels addr->dmlstat = DML_ON; 73230349Skarels if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit))) 73330341Skarels tp->t_state |= TS_CARR_ON; 73430341Skarels addr->dmcsr = DM_IE|DM_SE; 73539061Smarc if (tp->t_state&TS_CARR_ON || flag&O_NONBLOCK || 73639061Smarc tp->t_cflag&CLOCAL) 73730341Skarels break; 738*40729Skarels if (error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 739*40729Skarels ttopen, 0)) 740*40729Skarels break; 74130341Skarels } 7423792Swnj splx(s); 743*40729Skarels return (error); 7442468Swnj } 7452468Swnj 7462468Swnj /* 7472468Swnj * Dump control bits into the DM registers. 7482468Swnj */ 7492468Swnj dmctl(dev, bits, how) 7502468Swnj dev_t dev; 7512468Swnj int bits, how; 7522468Swnj { 7532974Swnj register struct uba_device *ui; 7542468Swnj register struct dmdevice *addr; 7552468Swnj register int unit, s; 7562468Swnj int dm; 7572468Swnj 7582468Swnj unit = minor(dev); 7592468Swnj dm = unit >> 4; 7602468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7612468Swnj return; 7622468Swnj addr = (struct dmdevice *)ui->ui_addr; 7632468Swnj s = spl5(); 7642479Swnj addr->dmcsr &= ~DM_SE; 7652479Swnj while (addr->dmcsr & DM_BUSY) 7662468Swnj ; 7672468Swnj addr->dmcsr = unit & 0xf; 7682468Swnj switch(how) { 7692468Swnj case DMSET: 7702468Swnj addr->dmlstat = bits; 7712468Swnj break; 7722468Swnj case DMBIS: 7732468Swnj addr->dmlstat |= bits; 7742468Swnj break; 7752468Swnj case DMBIC: 7762468Swnj addr->dmlstat &= ~bits; 7772468Swnj break; 7782468Swnj } 7793792Swnj addr->dmcsr = DM_IE|DM_SE; 7802468Swnj splx(s); 7812468Swnj } 7822468Swnj 7832468Swnj /* 7842468Swnj * DM11 interrupt; deal with carrier transitions. 7852468Swnj */ 7862468Swnj dmintr(dm) 7872468Swnj register int dm; 7882468Swnj { 7892974Swnj register struct uba_device *ui; 7902468Swnj register struct tty *tp; 7912468Swnj register struct dmdevice *addr; 79216942Skarels int unit; 7932468Swnj 7942468Swnj ui = dminfo[dm]; 7952479Swnj if (ui == 0) 7962479Swnj return; 7972468Swnj addr = (struct dmdevice *)ui->ui_addr; 7983997Sroot if (addr->dmcsr&DM_DONE) { 7993997Sroot if (addr->dmcsr&DM_CF) { 80016942Skarels unit = addr->dmcsr & 0xf; 80116942Skarels tp = &dh11[(dm << 4) + unit]; 80225394Skarels if (addr->dmlstat & DML_CAR) 80325394Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 80425394Skarels else if ((dhsoftCAR[dm] & (1<<unit)) == 0 && 80525394Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 80625394Skarels addr->dmlstat = 0; 8073997Sroot } 8083997Sroot addr->dmcsr = DM_IE|DM_SE; 8092468Swnj } 8102468Swnj } 8112625Swnj #endif 812