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*45804Sbostic * @(#)dh.c 7.15 (Berkeley) 12/16/90 723320Smckusick */ 813Sbill 91934Swnj #include "dh.h" 102643Swnj #if NDH > 0 1113Sbill /* 122479Swnj * DH-11/DM-11 driver 1313Sbill */ 14*45804Sbostic #include "../include/pte.h" 159771Ssam 16*45804Sbostic #include "sys/param.h" 1716062Skarels #include "uba.h" 18*45804Sbostic #include "sys/conf.h" 19*45804Sbostic #include "sys/user.h" 20*45804Sbostic #include "sys/proc.h" 21*45804Sbostic #include "sys/ioctl.h" 22*45804Sbostic #include "sys/tty.h" 23*45804Sbostic #include "sys/map.h" 24*45804Sbostic #include "sys/buf.h" 25*45804Sbostic #include "sys/vm.h" 26*45804Sbostic #include "sys/kernel.h" 27*45804Sbostic #include "sys/syslog.h" 288472Sroot 2917122Sbloom #include "ubareg.h" 3017122Sbloom #include "ubavar.h" 3117122Sbloom #include "dhreg.h" 3217122Sbloom #include "dmreg.h" 338472Sroot 34*45804Sbostic #include "sys/bkmac.h" 35*45804Sbostic #include "sys/clist.h" 36*45804Sbostic #include "sys/file.h" 37*45804Sbostic #include "sys/uio.h" 3813Sbill 392468Swnj /* 402479Swnj * Definition of the driver for the auto-configuration program. 412479Swnj * There is one definition for the dh and one for the dm. 422468Swnj */ 4316190Skarels int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer(); 442974Swnj struct uba_device *dhinfo[NDH]; 452395Swnj u_short dhstd[] = { 0 }; 462395Swnj struct uba_driver dhdriver = 472605Swnj { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; 482395Swnj 492605Swnj int dmprobe(), dmattach(), dmintr(); 502974Swnj struct uba_device *dminfo[NDH]; 512479Swnj u_short dmstd[] = { 0 }; 522479Swnj struct uba_driver dmdriver = 532605Swnj { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; 5413Sbill 556615Ssam #ifndef PORTSELECTOR 5639061Smarc #define ISPEED TTYDEF_SPEED 5739061Smarc #define LFLAG TTYDEF_LFLAG 586615Ssam #else 596615Ssam #define ISPEED B4800 6039061Smarc #define LFLAG (TTYDEF_LFLAG&~ECHO) 616615Ssam #endif 626615Ssam 6316190Skarels #define FASTTIMER (hz/30) /* scan rate with silos on */ 6416190Skarels 6513Sbill /* 662479Swnj * Local variables for the driver 6713Sbill */ 682643Swnj short dhsar[NDH]; /* software copy of last bar */ 692643Swnj short dhsoftCAR[NDH]; 7013Sbill 712643Swnj struct tty dh11[NDH*16]; 722643Swnj int ndh11 = NDH*16; 732479Swnj int dhact; /* mask of active dh's */ 7416190Skarels int dhsilos; /* mask of dh's with silo in use */ 7516190Skarels int dhchars[NDH]; /* recent input count */ 7616190Skarels int dhrate[NDH]; /* smoothed input count */ 7716190Skarels int dhhighrate = 100; /* silo on if dhchars > dhhighrate */ 7816190Skarels int dhlowrate = 75; /* silo off if dhrate < dhlowrate */ 7916190Skarels static short timerstarted; 802479Swnj int dhstart(), ttrstrt(); 8113Sbill 8239061Smarc struct speedtab dhspeedtab[] = { 8339061Smarc 19200, 14, 8439061Smarc 9600, 13, 8539061Smarc 4800, 12, 8639061Smarc 2400, 11, 8739061Smarc 1800, 10, 8839061Smarc 1200, 9, 8939061Smarc 600, 8, 9039061Smarc 300, 7, 9139061Smarc 200, 6, 9239061Smarc 150, 5, 9339061Smarc 134, 4, 9439061Smarc 110, 3, 9539061Smarc 75, 2, 9639061Smarc 50, 1, 9739061Smarc 0, 0, 9839061Smarc EXTA, 14, 9939061Smarc EXTB, 15, 10039061Smarc -1, -1 10139061Smarc }; 10239061Smarc 1032479Swnj /* 10430322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS. 10530322Skarels * The identity of the board which allocated resources is recorded, 10630322Skarels * so the process may be repeated after UNIBUS resets. 1072479Swnj * The UBACVT macro converts a clist space address for unibus uban 1082479Swnj * into an i/o space address for the DMA routine. 1092479Swnj */ 11030322Skarels int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */ 11130322Skarels int cbase[NUBA]; /* base address of clists in unibus map */ 1122479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 11313Sbill 1142456Swnj /* 1152456Swnj * Routine for configuration to force a dh to interrupt. 1162456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1172456Swnj */ 1182468Swnj /*ARGSUSED*/ 1192605Swnj dhprobe(reg) 1202395Swnj caddr_t reg; 1212395Swnj { 1222468Swnj register int br, cvec; /* these are ``value-result'' */ 1232479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1242395Swnj 1252605Swnj #ifdef lint 1262605Swnj br = 0; cvec = br; br = cvec; 1277384Sroot if (ndh11 == 0) ndh11 = 1; 1284932Swnj dhrint(0); dhxint(0); 1292605Swnj #endif 1302696Swnj #ifndef notdef 1312566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1326380Swnj DELAY(1000); 1337384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1342566Swnj dhaddr->un.dhcsr = 0; 1352566Swnj #else 1362456Swnj dhaddr->un.dhcsr = DH_TIE; 1372456Swnj DELAY(5); 1382456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1392421Skre dhaddr->dhbcr = -1; 1402456Swnj dhaddr->dhcar = 0; 1412421Skre dhaddr->dhbar = 1; 1422456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1432421Skre dhaddr->un.dhcsr = 0; 1442456Swnj if (cvec && cvec != 0x200) 1452456Swnj cvec -= 4; /* transmit -> receive */ 1462482Swnj #endif 1477408Skre return (sizeof (struct dhdevice)); 1482395Swnj } 1492395Swnj 1502456Swnj /* 1512605Swnj * Routine called to attach a dh. 1522456Swnj */ 1532605Swnj dhattach(ui) 1542974Swnj struct uba_device *ui; 1552395Swnj { 1562395Swnj 1572566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 15826219Skarels cbase[ui->ui_ubanum] = -1; 15936610Sbostic dh_uballoc[ui->ui_ubanum] = -1; 1602395Swnj } 1612395Swnj 16213Sbill /* 1632479Swnj * Configuration routine to cause a dm to interrupt. 1642479Swnj */ 1652605Swnj dmprobe(reg) 1662605Swnj caddr_t reg; 1672479Swnj { 1682479Swnj register int br, vec; /* value-result */ 1692605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1702479Swnj 1712605Swnj #ifdef lint 1723101Swnj br = 0; vec = br; br = vec; 1736185Ssam dmintr(0); 1742605Swnj #endif 1752479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1762479Swnj DELAY(20); 1772479Swnj dmaddr->dmcsr = 0; 1782605Swnj return (1); 1792479Swnj } 1802479Swnj 1812605Swnj /*ARGSUSED*/ 1822605Swnj dmattach(ui) 1832974Swnj struct uba_device *ui; 1842479Swnj { 1852479Swnj 1862479Swnj /* no local state to set up */ 1872479Swnj } 1882479Swnj 1892479Swnj /* 1902468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1912468Swnj * is the first dh on this uba. Turn on this dh if this is 1922468Swnj * the first use of it. Also do a dmopen to wait for carrier. 19313Sbill */ 19413Sbill /*ARGSUSED*/ 19513Sbill dhopen(dev, flag) 1962395Swnj dev_t dev; 19713Sbill { 19813Sbill register struct tty *tp; 1992395Swnj register int unit, dh; 2002479Swnj register struct dhdevice *addr; 2012974Swnj register struct uba_device *ui; 20240729Skarels int s, error; 20339061Smarc int dhparam(); 20413Sbill 2052395Swnj unit = minor(dev); 2062395Swnj dh = unit >> 4; 2078566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 2088566Sroot return (ENXIO); 2092395Swnj tp = &dh11[unit]; 2108566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 2118566Sroot return (EBUSY); 2122479Swnj addr = (struct dhdevice *)ui->ui_addr; 21313Sbill tp->t_addr = (caddr_t)addr; 21413Sbill tp->t_oproc = dhstart; 21539061Smarc tp->t_param = dhparam; 21639061Smarc tp->t_dev = dev; 2172468Swnj /* 2182468Swnj * While setting up state for this uba and this dh, 2192468Swnj * block uba resets which can clear the state. 2202468Swnj */ 2212468Swnj s = spl5(); 22226219Skarels if (cbase[ui->ui_ubanum] == -1) { 22330322Skarels dh_uballoc[ui->ui_ubanum] = dh; 22430322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, 22530322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); 22613Sbill } 22716190Skarels if (timerstarted == 0) { 22816190Skarels timerstarted++; 22916190Skarels timeout(dhtimer, (caddr_t) 0, hz); 23016190Skarels } 2312456Swnj if ((dhact&(1<<dh)) == 0) { 2322456Swnj addr->un.dhcsr |= DH_IE; 2332468Swnj dhact |= (1<<dh); 23416190Skarels addr->dhsilo = 0; 2352456Swnj } 23613Sbill splx(s); 2372468Swnj /* 23827049Skarels * If this is first open, initialize tty state to default. 2392468Swnj */ 2405406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 24144393Smarc tp->t_state |= TS_WOPEN; 24213Sbill ttychars(tp); 24327049Skarels #ifndef PORTSELECTOR 24427049Skarels if (tp->t_ispeed == 0) { 24539061Smarc #endif 24639061Smarc tp->t_iflag = TTYDEF_IFLAG; 24739061Smarc tp->t_oflag = TTYDEF_OFLAG; 24839061Smarc tp->t_cflag = TTYDEF_CFLAG; 24939061Smarc tp->t_lflag = LFLAG; 25039061Smarc tp->t_ispeed = tp->t_ospeed = ISPEED; 25139061Smarc #ifdef PORTSELECTOR 25239061Smarc tp->t_cflag |= HUPCL; 25327049Skarels #else 25427049Skarels } 25539061Smarc #endif 25639061Smarc dhparam(tp, &tp->t_termios); 25739061Smarc ttsetwater(tp); 25813Sbill } 2592468Swnj /* 2602468Swnj * Wait for carrier, then process line discipline specific open. 2612468Swnj */ 26240729Skarels if (error = dmopen(dev, flag)) 26340729Skarels return (error); 2648566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 26513Sbill } 26613Sbill 26713Sbill /* 2682468Swnj * Close a DH11 line, turning off the DM11. 26913Sbill */ 27013Sbill /*ARGSUSED*/ 27113Sbill dhclose(dev, flag) 2722395Swnj dev_t dev; 2732395Swnj int flag; 27413Sbill { 27513Sbill register struct tty *tp; 2762395Swnj register unit; 27713Sbill 2782395Swnj unit = minor(dev); 2792395Swnj tp = &dh11[unit]; 28013Sbill (*linesw[tp->t_line].l_close)(tp); 2812479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 28239061Smarc if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0) 2832479Swnj dmctl(unit, DML_OFF, DMSET); 28440729Skarels return (ttyclose(tp)); 28513Sbill } 28613Sbill 28739061Smarc dhread(dev, uio, flag) 2882395Swnj dev_t dev; 2897725Sroot struct uio *uio; 29013Sbill { 2918490Sroot register struct tty *tp = &dh11[minor(dev)]; 29213Sbill 29339061Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 29413Sbill } 29513Sbill 29639061Smarc dhwrite(dev, uio, flag) 2972395Swnj dev_t dev; 2987831Sroot struct uio *uio; 29913Sbill { 3008490Sroot register struct tty *tp = &dh11[minor(dev)]; 30113Sbill 30239061Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 30313Sbill } 30413Sbill 30513Sbill /* 30613Sbill * DH11 receiver interrupt. 30713Sbill */ 3082395Swnj dhrint(dh) 3092395Swnj int dh; 31013Sbill { 31113Sbill register struct tty *tp; 31239061Smarc register c, cc; 3132479Swnj register struct dhdevice *addr; 314117Sbill register struct tty *tp0; 3152974Swnj register struct uba_device *ui; 3162924Swnj int overrun = 0; 31713Sbill 3182395Swnj ui = dhinfo[dh]; 3192479Swnj if (ui == 0 || ui->ui_alive == 0) 3202479Swnj return; 3212479Swnj addr = (struct dhdevice *)ui->ui_addr; 3222468Swnj tp0 = &dh11[dh<<4]; 3232468Swnj /* 3242468Swnj * Loop fetching characters from the silo for this 3252468Swnj * dh until there are no more in the silo. 3262468Swnj */ 3272468Swnj while ((c = addr->dhrcr) < 0) { 3282468Swnj tp = tp0 + ((c>>8)&0xf); 32916190Skarels dhchars[dh]++; 3305406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 33125394Skarels wakeup((caddr_t)&tp->t_rawq); 33225394Skarels #ifdef PORTSELECTOR 33325394Skarels if ((tp->t_state&TS_WOPEN) == 0) 3346615Ssam #endif 33525394Skarels continue; 33613Sbill } 33739061Smarc cc = c&0xff; 33839061Smarc if (c&DH_PE) 33939061Smarc cc |= TTY_PE; 34039061Smarc if ((c&DH_DO) && overrun == 0) { 34124840Seric log(LOG_WARNING, "dh%d: silo overflow\n", dh); 3422924Swnj overrun = 1; 3432924Swnj } 34439061Smarc if (c&DH_FE) 34539061Smarc cc |= TTY_FE; 34639061Smarc (*linesw[tp->t_line].l_rint)(cc, tp); 34713Sbill } 34813Sbill } 34913Sbill 35013Sbill /* 3512468Swnj * Ioctl for DH11. 35213Sbill */ 35313Sbill /*ARGSUSED*/ 3547629Ssam dhioctl(dev, cmd, data, flag) 3557629Ssam caddr_t data; 35613Sbill { 35713Sbill register struct tty *tp; 3588566Sroot register int unit = minor(dev); 3598566Sroot int error; 36013Sbill 3612395Swnj tp = &dh11[unit]; 3628566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3638566Sroot if (error >= 0) 3648566Sroot return (error); 3658566Sroot error = ttioctl(tp, cmd, data, flag); 36639061Smarc if (error >= 0) 3678566Sroot return (error); 3688566Sroot switch (cmd) { 3697629Ssam 370168Sbill case TIOCSBRK: 3712479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 372168Sbill break; 3737629Ssam 374168Sbill case TIOCCBRK: 3752479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 376168Sbill break; 3777629Ssam 378168Sbill case TIOCSDTR: 3792479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 380168Sbill break; 3817629Ssam 382168Sbill case TIOCCDTR: 3832479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 384168Sbill break; 3857629Ssam 386168Sbill default: 3878566Sroot return (ENOTTY); 388168Sbill } 3898566Sroot return (0); 39013Sbill } 39113Sbill 39213Sbill /* 39313Sbill * Set parameters from open or stty into the DH hardware 39413Sbill * registers. 39513Sbill */ 39639061Smarc dhparam(tp, t) 39739061Smarc register struct tty *tp; 39839061Smarc register struct termios *t; 39913Sbill { 4002479Swnj register struct dhdevice *addr; 4012395Swnj register int lpar; 40239061Smarc register int cflag = t->c_cflag; 40339061Smarc int unit = minor(tp->t_dev); 404300Sbill int s; 40539061Smarc int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab); 40639061Smarc int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab); 40713Sbill 40839061Smarc /* check requested parameters */ 40939061Smarc if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5) 41039061Smarc return(EINVAL); 41139061Smarc if (ispeed == 0) 41239061Smarc ispeed = ospeed; 41339061Smarc /* and copy to tty */ 41439061Smarc tp->t_ispeed = t->c_ispeed; 41539061Smarc tp->t_ospeed = t->c_ospeed; 41639061Smarc tp->t_cflag = cflag; 4172468Swnj /* 4182468Swnj * Block interrupts so parameters will be set 4192468Swnj * before the line interrupts. 4202468Swnj */ 42139061Smarc addr = (struct dhdevice *)tp->t_addr; 422300Sbill s = spl5(); 4232468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 42439061Smarc if (ospeed == 0) { 42539061Smarc tp->t_cflag |= HUPCL; 4262479Swnj dmctl(unit, DML_OFF, DMSET); 42728147Skarels splx(s); 42839061Smarc return 0; 42913Sbill } 43039061Smarc lpar = (ospeed<<10) | (ispeed<<6); 43139061Smarc switch (cflag&CSIZE) { 43239061Smarc case CS6: lpar |= BITS6; break; 43339061Smarc case CS7: lpar |= BITS7; break; 43439061Smarc case CS8: lpar |= BITS8; break; 43539061Smarc } 43639061Smarc if (cflag&PARENB) 43739061Smarc lpar |= PENABLE; 43839061Smarc if (cflag&PARODD) 4392395Swnj lpar |= OPAR; 44039061Smarc if (cflag&CSTOPB) 4412395Swnj lpar |= TWOSB; 4422395Swnj addr->dhlpr = lpar; 443300Sbill splx(s); 44439061Smarc return 0; 44513Sbill } 44613Sbill 44713Sbill /* 44813Sbill * DH11 transmitter interrupt. 44913Sbill * Restart each line which used to be active but has 45013Sbill * terminated transmission since the last interrupt. 45113Sbill */ 4522395Swnj dhxint(dh) 4532395Swnj int dh; 45413Sbill { 45513Sbill register struct tty *tp; 4562479Swnj register struct dhdevice *addr; 45713Sbill short ttybit, bar, *sbar; 4582974Swnj register struct uba_device *ui; 4592468Swnj register int unit; 4602605Swnj u_short cntr; 46113Sbill 4622395Swnj ui = dhinfo[dh]; 4632479Swnj addr = (struct dhdevice *)ui->ui_addr; 4642456Swnj if (addr->un.dhcsr & DH_NXM) { 4652456Swnj addr->un.dhcsr |= DH_CNI; 4662924Swnj printf("dh%d: NXM\n", dh); 467105Sbill } 4682395Swnj sbar = &dhsar[dh]; 46913Sbill bar = *sbar & ~addr->dhbar; 4702395Swnj unit = dh * 16; ttybit = 1; 4712468Swnj addr->un.dhcsr &= (short)~DH_TI; 4722468Swnj for (; bar; unit++, ttybit <<= 1) { 4732468Swnj if (bar & ttybit) { 47413Sbill *sbar &= ~ttybit; 47513Sbill bar &= ~ttybit; 4762395Swnj tp = &dh11[unit]; 4775406Swnj tp->t_state &= ~TS_BUSY; 4785406Swnj if (tp->t_state&TS_FLUSH) 4795406Swnj tp->t_state &= ~TS_FLUSH; 480113Sbill else { 4812456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4822468Swnj /* 4832468Swnj * Do arithmetic in a short to make up 4842468Swnj * for lost 16&17 bits. 4852468Swnj */ 4862605Swnj cntr = addr->dhcar - 4872468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4883101Swnj ndflush(&tp->t_outq, (int)cntr); 489113Sbill } 490113Sbill if (tp->t_line) 49113Sbill (*linesw[tp->t_line].l_start)(tp); 492113Sbill else 49313Sbill dhstart(tp); 49413Sbill } 49513Sbill } 49613Sbill } 49713Sbill 49813Sbill /* 49913Sbill * Start (restart) transmission on the given DH11 line. 50013Sbill */ 50113Sbill dhstart(tp) 5022395Swnj register struct tty *tp; 50313Sbill { 5042479Swnj register struct dhdevice *addr; 5052468Swnj register int car, dh, unit, nch; 5062395Swnj int s; 50713Sbill 5082468Swnj unit = minor(tp->t_dev); 5092468Swnj dh = unit >> 4; 5102468Swnj unit &= 0xf; 5112479Swnj addr = (struct dhdevice *)tp->t_addr; 5122468Swnj 51313Sbill /* 5142468Swnj * Must hold interrupts in following code to prevent 5152468Swnj * state of the tp from changing. 51613Sbill */ 51713Sbill s = spl5(); 5182468Swnj /* 5192468Swnj * If it's currently active, or delaying, no need to do anything. 5202468Swnj */ 5215406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 52213Sbill goto out; 5232468Swnj /* 5242468Swnj * If there are sleepers, and output has drained below low 5252468Swnj * water mark, wake up the sleepers. 5262468Swnj */ 52739061Smarc if (tp->t_outq.c_cc<=tp->t_lowat) { 5285406Swnj if (tp->t_state&TS_ASLEEP) { 5295406Swnj tp->t_state &= ~TS_ASLEEP; 5305406Swnj wakeup((caddr_t)&tp->t_outq); 5315406Swnj } 5325406Swnj if (tp->t_wsel) { 5335406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5345406Swnj tp->t_wsel = 0; 5355406Swnj tp->t_state &= ~TS_WCOLL; 5365406Swnj } 53713Sbill } 5382468Swnj /* 5392468Swnj * Now restart transmission unless the output queue is 5402468Swnj * empty. 5412468Swnj */ 54213Sbill if (tp->t_outq.c_cc == 0) 54313Sbill goto out; 54439061Smarc if (1 || !(tp->t_oflag&OPOST)) /*XXX*/ 54513Sbill nch = ndqb(&tp->t_outq, 0); 5462395Swnj else { 54713Sbill nch = ndqb(&tp->t_outq, 0200); 5482468Swnj /* 5492468Swnj * If first thing on queue is a delay process it. 5502468Swnj */ 55113Sbill if (nch == 0) { 55213Sbill nch = getc(&tp->t_outq); 5532468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5545406Swnj tp->t_state |= TS_TIMEOUT; 55513Sbill goto out; 55613Sbill } 55713Sbill } 5582468Swnj /* 5592468Swnj * If characters to transmit, restart transmission. 5602468Swnj */ 56113Sbill if (nch) { 5622468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5632468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5643586Sroot /* 5653586Sroot * The following nonsense with short word 5663586Sroot * is to make sure the dhbar |= word below 5673586Sroot * is done with an interlocking bisw2 instruction. 5683586Sroot */ 5693586Sroot { short word = 1 << unit; 5703586Sroot dhsar[dh] |= word; 5712468Swnj addr->dhcar = car; 57213Sbill addr->dhbcr = -nch; 5733586Sroot addr->dhbar |= word; 5743586Sroot } 5755406Swnj tp->t_state |= TS_BUSY; 57613Sbill } 5772395Swnj out: 57813Sbill splx(s); 57913Sbill } 58013Sbill 58113Sbill /* 5822468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 58313Sbill */ 58413Sbill /*ARGSUSED*/ 58513Sbill dhstop(tp, flag) 5862468Swnj register struct tty *tp; 58713Sbill { 5882479Swnj register struct dhdevice *addr; 5892395Swnj register int unit, s; 59013Sbill 5912479Swnj addr = (struct dhdevice *)tp->t_addr; 5922468Swnj /* 5932468Swnj * Block input/output interrupts while messing with state. 5942468Swnj */ 5952468Swnj s = spl5(); 5965406Swnj if (tp->t_state & TS_BUSY) { 5972468Swnj /* 5982468Swnj * Device is transmitting; stop output 5992468Swnj * by selecting the line and setting the byte 6002468Swnj * count to -1. We will clean up later 6012468Swnj * by examining the address where the dh stopped. 6022468Swnj */ 6032395Swnj unit = minor(tp->t_dev); 6042456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 6055406Swnj if ((tp->t_state&TS_TTSTOP)==0) 6065406Swnj tp->t_state |= TS_FLUSH; 607113Sbill addr->dhbcr = -1; 608113Sbill } 60913Sbill splx(s); 61013Sbill } 61113Sbill 612168Sbill /* 613280Sbill * Reset state of driver if UBA reset was necessary. 614280Sbill * Reset the csrl and lpr registers on open lines, and 615280Sbill * restart transmitters. 616280Sbill */ 6172395Swnj dhreset(uban) 6182468Swnj int uban; 619280Sbill { 6202395Swnj register int dh, unit; 621280Sbill register struct tty *tp; 6222974Swnj register struct uba_device *ui; 6232421Skre int i; 624280Sbill 6252395Swnj dh = 0; 6262643Swnj for (dh = 0; dh < NDH; dh++) { 6272421Skre ui = dhinfo[dh]; 6282421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6292421Skre continue; 6302924Swnj printf(" dh%d", dh); 63130322Skarels if (dh_uballoc[uban] == dh) { 63230322Skarels int info; 63330322Skarels 63430322Skarels info = uballoc(uban, (caddr_t)cfree, 63530322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 63630322Skarels if (info) 63730322Skarels cbase[uban] = UBAI_ADDR(info); 63830322Skarels else { 63930322Skarels printf(" [can't get uba map]"); 64030322Skarels cbase[uban] = -1; 64130322Skarels } 64225433Skarels } 6432479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 64416190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; 6452421Skre unit = dh * 16; 6462421Skre for (i = 0; i < 16; i++) { 6472421Skre tp = &dh11[unit]; 6485406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6492421Skre dhparam(unit); 6502479Swnj dmctl(unit, DML_ON, DMSET); 6515406Swnj tp->t_state &= ~TS_BUSY; 6522421Skre dhstart(tp); 6532421Skre } 6542421Skre unit++; 655300Sbill } 656300Sbill } 65716190Skarels dhsilos = 0; 658280Sbill } 6592395Swnj 66016190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 6612468Swnj /* 66216190Skarels * At software clock interrupt time, check status. 66316190Skarels * Empty all the dh silos that are in use, and decide whether 66416190Skarels * to turn any silos off or on. 6652468Swnj */ 6662456Swnj dhtimer() 6672456Swnj { 66816190Skarels register int dh, s; 66916190Skarels static int timercalls; 6702456Swnj 67116190Skarels if (dhsilos) { 67216190Skarels dhfasttimers++; /*DEBUG*/ 67316190Skarels timercalls++; 67416190Skarels s = spl5(); 67516190Skarels for (dh = 0; dh < NDH; dh++) 67616190Skarels if (dhsilos & (1 << dh)) 67716190Skarels dhrint(dh); 67816190Skarels splx(s); 67916190Skarels } 68016190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 68116190Skarels dhslowtimers++; /*DEBUG*/ 68216190Skarels timercalls = 0; 68316190Skarels for (dh = 0; dh < NDH; dh++) { 68416190Skarels ave(dhrate[dh], dhchars[dh], 8); 68516190Skarels if ((dhchars[dh] > dhhighrate) && 68616190Skarels ((dhsilos & (1 << dh)) == 0)) { 68716190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 68816190Skarels (dhchars[dh] > 500? 32 : 16); 68916190Skarels dhsilos |= (1 << dh); 69016190Skarels dhtransitions++; /*DEBUG*/ 69116190Skarels } else if ((dhsilos & (1 << dh)) && 69216190Skarels (dhrate[dh] < dhlowrate)) { 69316190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; 69416190Skarels dhsilos &= ~(1 << dh); 69516190Skarels } 69616190Skarels dhchars[dh] = 0; 69716190Skarels } 69816190Skarels } 69916190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); 7002456Swnj } 7012456Swnj 7022468Swnj /* 7032479Swnj * Turn on the line associated with dh dev. 7042468Swnj */ 70539061Smarc dmopen(dev, flag) 7062468Swnj dev_t dev; 7072468Swnj { 7082468Swnj register struct tty *tp; 7092468Swnj register struct dmdevice *addr; 7102974Swnj register struct uba_device *ui; 7112468Swnj register int unit; 7122468Swnj register int dm; 71340729Skarels int s, error = 0; 7142468Swnj 7152468Swnj unit = minor(dev); 7162479Swnj dm = unit >> 4; 7172468Swnj tp = &dh11[unit]; 7182566Swnj unit &= 0xf; 71916942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 7205406Swnj tp->t_state |= TS_CARR_ON; 72140729Skarels return (0); 7222468Swnj } 7232468Swnj addr = (struct dmdevice *)ui->ui_addr; 7243792Swnj s = spl5(); 72530341Skarels for (;;) { 72644393Smarc tp->t_state |= TS_WOPEN; 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; 73844393Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 73944393Smarc ttopen, 0)) 74040729Skarels break; 74130341Skarels } 7423792Swnj splx(s); 74340729Skarels 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