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*39061Smarc * @(#)dh.c 7.8 (Berkeley) 09/06/89 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 "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 58*39061Smarc #define ISPEED TTYDEF_SPEED 59*39061Smarc #define LFLAG TTYDEF_LFLAG 606615Ssam #else 616615Ssam #define ISPEED B4800 62*39061Smarc #define LFLAG (TTYDEF_LFLAG&~ECHO) 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 84*39061Smarc struct speedtab dhspeedtab[] = { 85*39061Smarc 19200, 14, 86*39061Smarc 9600, 13, 87*39061Smarc 4800, 12, 88*39061Smarc 2400, 11, 89*39061Smarc 1800, 10, 90*39061Smarc 1200, 9, 91*39061Smarc 600, 8, 92*39061Smarc 300, 7, 93*39061Smarc 200, 6, 94*39061Smarc 150, 5, 95*39061Smarc 134, 4, 96*39061Smarc 110, 3, 97*39061Smarc 75, 2, 98*39061Smarc 50, 1, 99*39061Smarc 0, 0, 100*39061Smarc EXTA, 14, 101*39061Smarc EXTB, 15, 102*39061Smarc -1, -1 103*39061Smarc }; 104*39061Smarc 1052479Swnj /* 10630322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS. 10730322Skarels * The identity of the board which allocated resources is recorded, 10830322Skarels * so the process may be repeated after UNIBUS resets. 1092479Swnj * The UBACVT macro converts a clist space address for unibus uban 1102479Swnj * into an i/o space address for the DMA routine. 1112479Swnj */ 11230322Skarels int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */ 11330322Skarels int cbase[NUBA]; /* base address of clists in unibus map */ 1142479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 11513Sbill 1162456Swnj /* 1172456Swnj * Routine for configuration to force a dh to interrupt. 1182456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1192456Swnj */ 1202468Swnj /*ARGSUSED*/ 1212605Swnj dhprobe(reg) 1222395Swnj caddr_t reg; 1232395Swnj { 1242468Swnj register int br, cvec; /* these are ``value-result'' */ 1252479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1262395Swnj 1272605Swnj #ifdef lint 1282605Swnj br = 0; cvec = br; br = cvec; 1297384Sroot if (ndh11 == 0) ndh11 = 1; 1304932Swnj dhrint(0); dhxint(0); 1312605Swnj #endif 1322696Swnj #ifndef notdef 1332566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1346380Swnj DELAY(1000); 1357384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1362566Swnj dhaddr->un.dhcsr = 0; 1372566Swnj #else 1382456Swnj dhaddr->un.dhcsr = DH_TIE; 1392456Swnj DELAY(5); 1402456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1412421Skre dhaddr->dhbcr = -1; 1422456Swnj dhaddr->dhcar = 0; 1432421Skre dhaddr->dhbar = 1; 1442456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1452421Skre dhaddr->un.dhcsr = 0; 1462456Swnj if (cvec && cvec != 0x200) 1472456Swnj cvec -= 4; /* transmit -> receive */ 1482482Swnj #endif 1497408Skre return (sizeof (struct dhdevice)); 1502395Swnj } 1512395Swnj 1522456Swnj /* 1532605Swnj * Routine called to attach a dh. 1542456Swnj */ 1552605Swnj dhattach(ui) 1562974Swnj struct uba_device *ui; 1572395Swnj { 1582395Swnj 1592566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 16026219Skarels cbase[ui->ui_ubanum] = -1; 16136610Sbostic dh_uballoc[ui->ui_ubanum] = -1; 1622395Swnj } 1632395Swnj 16413Sbill /* 1652479Swnj * Configuration routine to cause a dm to interrupt. 1662479Swnj */ 1672605Swnj dmprobe(reg) 1682605Swnj caddr_t reg; 1692479Swnj { 1702479Swnj register int br, vec; /* value-result */ 1712605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1722479Swnj 1732605Swnj #ifdef lint 1743101Swnj br = 0; vec = br; br = vec; 1756185Ssam dmintr(0); 1762605Swnj #endif 1772479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1782479Swnj DELAY(20); 1792479Swnj dmaddr->dmcsr = 0; 1802605Swnj return (1); 1812479Swnj } 1822479Swnj 1832605Swnj /*ARGSUSED*/ 1842605Swnj dmattach(ui) 1852974Swnj struct uba_device *ui; 1862479Swnj { 1872479Swnj 1882479Swnj /* no local state to set up */ 1892479Swnj } 1902479Swnj 1912479Swnj /* 1922468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1932468Swnj * is the first dh on this uba. Turn on this dh if this is 1942468Swnj * the first use of it. Also do a dmopen to wait for carrier. 19513Sbill */ 19613Sbill /*ARGSUSED*/ 19713Sbill dhopen(dev, flag) 1982395Swnj dev_t dev; 19913Sbill { 20013Sbill register struct tty *tp; 2012395Swnj register int unit, dh; 2022479Swnj register struct dhdevice *addr; 2032974Swnj register struct uba_device *ui; 20413Sbill int s; 205*39061Smarc int dhparam(); 20613Sbill 2072395Swnj unit = minor(dev); 2082395Swnj dh = unit >> 4; 2098566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 2108566Sroot return (ENXIO); 2112395Swnj tp = &dh11[unit]; 2128566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2138566Sroot return (EBUSY); 2142479Swnj addr = (struct dhdevice *)ui->ui_addr; 21513Sbill tp->t_addr = (caddr_t)addr; 21613Sbill tp->t_oproc = dhstart; 217*39061Smarc tp->t_param = dhparam; 218*39061Smarc tp->t_dev = dev; 2195406Swnj tp->t_state |= TS_WOPEN; 2202468Swnj /* 2212468Swnj * While setting up state for this uba and this dh, 2222468Swnj * block uba resets which can clear the state. 2232468Swnj */ 2242468Swnj s = spl5(); 22526219Skarels if (cbase[ui->ui_ubanum] == -1) { 22630322Skarels dh_uballoc[ui->ui_ubanum] = dh; 22730322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, 22830322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); 22913Sbill } 23016190Skarels if (timerstarted == 0) { 23116190Skarels timerstarted++; 23216190Skarels timeout(dhtimer, (caddr_t) 0, hz); 23316190Skarels } 2342456Swnj if ((dhact&(1<<dh)) == 0) { 2352456Swnj addr->un.dhcsr |= DH_IE; 2362468Swnj dhact |= (1<<dh); 23716190Skarels addr->dhsilo = 0; 2382456Swnj } 23913Sbill splx(s); 2402468Swnj /* 24127049Skarels * If this is first open, initialize tty state to default. 2422468Swnj */ 2435406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 24413Sbill ttychars(tp); 24527049Skarels #ifndef PORTSELECTOR 24627049Skarels if (tp->t_ispeed == 0) { 247*39061Smarc #endif 248*39061Smarc tp->t_iflag = TTYDEF_IFLAG; 249*39061Smarc tp->t_oflag = TTYDEF_OFLAG; 250*39061Smarc tp->t_cflag = TTYDEF_CFLAG; 251*39061Smarc tp->t_lflag = LFLAG; 252*39061Smarc tp->t_ispeed = tp->t_ospeed = ISPEED; 253*39061Smarc #ifdef PORTSELECTOR 254*39061Smarc tp->t_cflag |= HUPCL; 25527049Skarels #else 25627049Skarels } 257*39061Smarc #endif 258*39061Smarc dhparam(tp, &tp->t_termios); 259*39061Smarc ttsetwater(tp); 26013Sbill } 2612468Swnj /* 2622468Swnj * Wait for carrier, then process line discipline specific open. 2632468Swnj */ 264*39061Smarc dmopen(dev, flag); 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)); 283*39061Smarc if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0) 2842479Swnj dmctl(unit, DML_OFF, DMSET); 28513Sbill ttyclose(tp); 28613Sbill } 28713Sbill 288*39061Smarc dhread(dev, uio, flag) 2892395Swnj dev_t dev; 2907725Sroot struct uio *uio; 29113Sbill { 2928490Sroot register struct tty *tp = &dh11[minor(dev)]; 29313Sbill 294*39061Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 29513Sbill } 29613Sbill 297*39061Smarc dhwrite(dev, uio, flag) 2982395Swnj dev_t dev; 2997831Sroot struct uio *uio; 30013Sbill { 3018490Sroot register struct tty *tp = &dh11[minor(dev)]; 30213Sbill 303*39061Smarc 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; 313*39061Smarc 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 } 338*39061Smarc cc = c&0xff; 339*39061Smarc if (c&DH_PE) 340*39061Smarc cc |= TTY_PE; 341*39061Smarc if ((c&DH_DO) && overrun == 0) { 34224840Seric log(LOG_WARNING, "dh%d: silo overflow\n", dh); 3432924Swnj overrun = 1; 3442924Swnj } 345*39061Smarc if (c&DH_FE) 346*39061Smarc cc |= TTY_FE; 347*39061Smarc (*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); 367*39061Smarc 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 */ 397*39061Smarc dhparam(tp, t) 398*39061Smarc register struct tty *tp; 399*39061Smarc register struct termios *t; 40013Sbill { 4012479Swnj register struct dhdevice *addr; 4022395Swnj register int lpar; 403*39061Smarc register int cflag = t->c_cflag; 404*39061Smarc int unit = minor(tp->t_dev); 405300Sbill int s; 406*39061Smarc int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab); 407*39061Smarc int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab); 40813Sbill 409*39061Smarc /* check requested parameters */ 410*39061Smarc if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5) 411*39061Smarc return(EINVAL); 412*39061Smarc if (ispeed == 0) 413*39061Smarc ispeed = ospeed; 414*39061Smarc /* and copy to tty */ 415*39061Smarc tp->t_ispeed = t->c_ispeed; 416*39061Smarc tp->t_ospeed = t->c_ospeed; 417*39061Smarc tp->t_cflag = cflag; 4182468Swnj /* 4192468Swnj * Block interrupts so parameters will be set 4202468Swnj * before the line interrupts. 4212468Swnj */ 422*39061Smarc addr = (struct dhdevice *)tp->t_addr; 423300Sbill s = spl5(); 4242468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 425*39061Smarc if (ospeed == 0) { 426*39061Smarc tp->t_cflag |= HUPCL; 4272479Swnj dmctl(unit, DML_OFF, DMSET); 42828147Skarels splx(s); 429*39061Smarc return 0; 43013Sbill } 431*39061Smarc lpar = (ospeed<<10) | (ispeed<<6); 432*39061Smarc switch (cflag&CSIZE) { 433*39061Smarc case CS6: lpar |= BITS6; break; 434*39061Smarc case CS7: lpar |= BITS7; break; 435*39061Smarc case CS8: lpar |= BITS8; break; 436*39061Smarc } 437*39061Smarc if (cflag&PARENB) 438*39061Smarc lpar |= PENABLE; 439*39061Smarc if (cflag&PARODD) 4402395Swnj lpar |= OPAR; 441*39061Smarc if (cflag&CSTOPB) 4422395Swnj lpar |= TWOSB; 4432395Swnj addr->dhlpr = lpar; 444300Sbill splx(s); 445*39061Smarc 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 */ 528*39061Smarc 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; 545*39061Smarc 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 */ 706*39061Smarc 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; 7143792Swnj int s; 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; 7222468Swnj return; 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; 735*39061Smarc if (tp->t_state&TS_CARR_ON || flag&O_NONBLOCK || 736*39061Smarc tp->t_cflag&CLOCAL) 73730341Skarels break; 7382468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 73930341Skarels } 7403792Swnj splx(s); 7412468Swnj } 7422468Swnj 7432468Swnj /* 7442468Swnj * Dump control bits into the DM registers. 7452468Swnj */ 7462468Swnj dmctl(dev, bits, how) 7472468Swnj dev_t dev; 7482468Swnj int bits, how; 7492468Swnj { 7502974Swnj register struct uba_device *ui; 7512468Swnj register struct dmdevice *addr; 7522468Swnj register int unit, s; 7532468Swnj int dm; 7542468Swnj 7552468Swnj unit = minor(dev); 7562468Swnj dm = unit >> 4; 7572468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7582468Swnj return; 7592468Swnj addr = (struct dmdevice *)ui->ui_addr; 7602468Swnj s = spl5(); 7612479Swnj addr->dmcsr &= ~DM_SE; 7622479Swnj while (addr->dmcsr & DM_BUSY) 7632468Swnj ; 7642468Swnj addr->dmcsr = unit & 0xf; 7652468Swnj switch(how) { 7662468Swnj case DMSET: 7672468Swnj addr->dmlstat = bits; 7682468Swnj break; 7692468Swnj case DMBIS: 7702468Swnj addr->dmlstat |= bits; 7712468Swnj break; 7722468Swnj case DMBIC: 7732468Swnj addr->dmlstat &= ~bits; 7742468Swnj break; 7752468Swnj } 7763792Swnj addr->dmcsr = DM_IE|DM_SE; 7772468Swnj splx(s); 7782468Swnj } 7792468Swnj 7802468Swnj /* 7812468Swnj * DM11 interrupt; deal with carrier transitions. 7822468Swnj */ 7832468Swnj dmintr(dm) 7842468Swnj register int dm; 7852468Swnj { 7862974Swnj register struct uba_device *ui; 7872468Swnj register struct tty *tp; 7882468Swnj register struct dmdevice *addr; 78916942Skarels int unit; 7902468Swnj 7912468Swnj ui = dminfo[dm]; 7922479Swnj if (ui == 0) 7932479Swnj return; 7942468Swnj addr = (struct dmdevice *)ui->ui_addr; 7953997Sroot if (addr->dmcsr&DM_DONE) { 7963997Sroot if (addr->dmcsr&DM_CF) { 79716942Skarels unit = addr->dmcsr & 0xf; 79816942Skarels tp = &dh11[(dm << 4) + unit]; 79925394Skarels if (addr->dmlstat & DML_CAR) 80025394Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 80125394Skarels else if ((dhsoftCAR[dm] & (1<<unit)) == 0 && 80225394Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 80325394Skarels addr->dmlstat = 0; 8043997Sroot } 8053997Sroot addr->dmcsr = DM_IE|DM_SE; 8062468Swnj } 8072468Swnj } 8082625Swnj #endif 809