123320Smckusick /* 223320Smckusick * Copyright (c) 1982 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*24840Seric * @(#)dh.c 6.11 (Berkeley) 09/17/85 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 586615Ssam #define ISPEED B300 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 /* 852479Swnj * The clist space is mapped by the driver onto each UNIBUS. 862479Swnj * The UBACVT macro converts a clist space address for unibus uban 872479Swnj * into an i/o space address for the DMA routine. 882479Swnj */ 8916062Skarels int dh_ubinfo[NUBA]; /* info about allocated unibus map */ 9016062Skarels int cbase[NUBA]; /* base address in unibus map */ 912479Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 9213Sbill 932456Swnj /* 942456Swnj * Routine for configuration to force a dh to interrupt. 952456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 962456Swnj */ 972468Swnj /*ARGSUSED*/ 982605Swnj dhprobe(reg) 992395Swnj caddr_t reg; 1002395Swnj { 1012468Swnj register int br, cvec; /* these are ``value-result'' */ 1022479Swnj register struct dhdevice *dhaddr = (struct dhdevice *)reg; 1032395Swnj 1042605Swnj #ifdef lint 1052605Swnj br = 0; cvec = br; br = cvec; 1067384Sroot if (ndh11 == 0) ndh11 = 1; 1074932Swnj dhrint(0); dhxint(0); 1082605Swnj #endif 1092696Swnj #ifndef notdef 1102566Swnj dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; 1116380Swnj DELAY(1000); 1127384Sroot dhaddr->un.dhcsr &= ~DH_RI; 1132566Swnj dhaddr->un.dhcsr = 0; 1142566Swnj #else 1152456Swnj dhaddr->un.dhcsr = DH_TIE; 1162456Swnj DELAY(5); 1172456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1182421Skre dhaddr->dhbcr = -1; 1192456Swnj dhaddr->dhcar = 0; 1202421Skre dhaddr->dhbar = 1; 1212456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1222421Skre dhaddr->un.dhcsr = 0; 1232456Swnj if (cvec && cvec != 0x200) 1242456Swnj cvec -= 4; /* transmit -> receive */ 1252482Swnj #endif 1267408Skre return (sizeof (struct dhdevice)); 1272395Swnj } 1282395Swnj 1292456Swnj /* 1302605Swnj * Routine called to attach a dh. 1312456Swnj */ 1322605Swnj dhattach(ui) 1332974Swnj struct uba_device *ui; 1342395Swnj { 1352395Swnj 1362566Swnj dhsoftCAR[ui->ui_unit] = ui->ui_flags; 1372395Swnj } 1382395Swnj 13913Sbill /* 1402479Swnj * Configuration routine to cause a dm to interrupt. 1412479Swnj */ 1422605Swnj dmprobe(reg) 1432605Swnj caddr_t reg; 1442479Swnj { 1452479Swnj register int br, vec; /* value-result */ 1462605Swnj register struct dmdevice *dmaddr = (struct dmdevice *)reg; 1472479Swnj 1482605Swnj #ifdef lint 1493101Swnj br = 0; vec = br; br = vec; 1506185Ssam dmintr(0); 1512605Swnj #endif 1522479Swnj dmaddr->dmcsr = DM_DONE|DM_IE; 1532479Swnj DELAY(20); 1542479Swnj dmaddr->dmcsr = 0; 1552605Swnj return (1); 1562479Swnj } 1572479Swnj 1582605Swnj /*ARGSUSED*/ 1592605Swnj dmattach(ui) 1602974Swnj struct uba_device *ui; 1612479Swnj { 1622479Swnj 1632479Swnj /* no local state to set up */ 1642479Swnj } 1652479Swnj 1662479Swnj /* 1672468Swnj * Open a DH11 line, mapping the clist onto the uba if this 1682468Swnj * is the first dh on this uba. Turn on this dh if this is 1692468Swnj * the first use of it. Also do a dmopen to wait for carrier. 17013Sbill */ 17113Sbill /*ARGSUSED*/ 17213Sbill dhopen(dev, flag) 1732395Swnj dev_t dev; 17413Sbill { 17513Sbill register struct tty *tp; 1762395Swnj register int unit, dh; 1772479Swnj register struct dhdevice *addr; 1782974Swnj register struct uba_device *ui; 17913Sbill int s; 18013Sbill 1812395Swnj unit = minor(dev); 1822395Swnj dh = unit >> 4; 1838566Sroot if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) 1848566Sroot return (ENXIO); 1852395Swnj tp = &dh11[unit]; 1868566Sroot if (tp->t_state&TS_XCLUDE && u.u_uid!=0) 1878566Sroot return (EBUSY); 1882479Swnj addr = (struct dhdevice *)ui->ui_addr; 18913Sbill tp->t_addr = (caddr_t)addr; 19013Sbill tp->t_oproc = dhstart; 1915406Swnj tp->t_state |= TS_WOPEN; 1922468Swnj /* 1932468Swnj * While setting up state for this uba and this dh, 1942468Swnj * block uba resets which can clear the state. 1952468Swnj */ 1962468Swnj s = spl5(); 1972421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 198717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1992395Swnj dh_ubinfo[ui->ui_ubanum] = 2002421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 2012770Swnj 512+nclist*sizeof(struct cblock), 0); 2022456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 20313Sbill } 20416190Skarels if (timerstarted == 0) { 20516190Skarels timerstarted++; 20616190Skarels timeout(dhtimer, (caddr_t) 0, hz); 20716190Skarels } 2082456Swnj if ((dhact&(1<<dh)) == 0) { 2092456Swnj addr->un.dhcsr |= DH_IE; 2102468Swnj dhact |= (1<<dh); 21116190Skarels addr->dhsilo = 0; 2122456Swnj } 21313Sbill splx(s); 2142468Swnj /* 2152468Swnj * If this is first open, initialze tty state to default. 2162468Swnj */ 2175406Swnj if ((tp->t_state&TS_ISOPEN) == 0) { 21813Sbill ttychars(tp); 2196615Ssam #ifndef PORTSELECTOR 220168Sbill if (tp->t_ispeed == 0) { 2216615Ssam #endif 2226615Ssam tp->t_ispeed = ISPEED; 2236615Ssam tp->t_ospeed = ISPEED; 2246615Ssam tp->t_flags = IFLAGS; 2256615Ssam #ifndef PORTSELECTOR 226168Sbill } 2276615Ssam #endif 2282395Swnj dhparam(unit); 22913Sbill } 2302468Swnj /* 2312468Swnj * Wait for carrier, then process line discipline specific open. 2322468Swnj */ 23313Sbill dmopen(dev); 2348566Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 23513Sbill } 23613Sbill 23713Sbill /* 2382468Swnj * Close a DH11 line, turning off the DM11. 23913Sbill */ 24013Sbill /*ARGSUSED*/ 24113Sbill dhclose(dev, flag) 2422395Swnj dev_t dev; 2432395Swnj int flag; 24413Sbill { 24513Sbill register struct tty *tp; 2462395Swnj register unit; 24713Sbill 2482395Swnj unit = minor(dev); 2492395Swnj tp = &dh11[unit]; 25013Sbill (*linesw[tp->t_line].l_close)(tp); 2512479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 2525406Swnj if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) 2532479Swnj dmctl(unit, DML_OFF, DMSET); 25413Sbill ttyclose(tp); 25513Sbill } 25613Sbill 2577725Sroot dhread(dev, uio) 2582395Swnj dev_t dev; 2597725Sroot struct uio *uio; 26013Sbill { 2618490Sroot register struct tty *tp = &dh11[minor(dev)]; 26213Sbill 2637725Sroot return ((*linesw[tp->t_line].l_read)(tp, uio)); 26413Sbill } 26513Sbill 2667831Sroot dhwrite(dev, uio) 2672395Swnj dev_t dev; 2687831Sroot struct uio *uio; 26913Sbill { 2708490Sroot register struct tty *tp = &dh11[minor(dev)]; 27113Sbill 2728490Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 27313Sbill } 27413Sbill 27513Sbill /* 27613Sbill * DH11 receiver interrupt. 27713Sbill */ 2782395Swnj dhrint(dh) 2792395Swnj int dh; 28013Sbill { 28113Sbill register struct tty *tp; 2822395Swnj register c; 2832479Swnj register struct dhdevice *addr; 284117Sbill register struct tty *tp0; 2852974Swnj register struct uba_device *ui; 2862924Swnj int overrun = 0; 28713Sbill 2882395Swnj ui = dhinfo[dh]; 2892479Swnj if (ui == 0 || ui->ui_alive == 0) 2902479Swnj return; 2912479Swnj addr = (struct dhdevice *)ui->ui_addr; 2922468Swnj tp0 = &dh11[dh<<4]; 2932468Swnj /* 2942468Swnj * Loop fetching characters from the silo for this 2952468Swnj * dh until there are no more in the silo. 2962468Swnj */ 2972468Swnj while ((c = addr->dhrcr) < 0) { 2982468Swnj tp = tp0 + ((c>>8)&0xf); 29916190Skarels dhchars[dh]++; 3006615Ssam #ifndef PORTSELECTOR 3015406Swnj if ((tp->t_state&TS_ISOPEN)==0) { 3026615Ssam #else 3036615Ssam if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { 3046615Ssam #endif 30513Sbill wakeup((caddr_t)tp); 30613Sbill continue; 30713Sbill } 3082468Swnj if (c & DH_PE) 30913Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 31013Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 31113Sbill continue; 3122924Swnj if ((c & DH_DO) && overrun == 0) { 313*24840Seric log(LOG_WARNING, "dh%d: silo overflow\n", dh); 3142924Swnj overrun = 1; 3152924Swnj } 3162468Swnj if (c & DH_FE) 3172468Swnj /* 3182468Swnj * At framing error (break) generate 3192468Swnj * a null (in raw mode, for getty), or a 3202468Swnj * interrupt (in cooked/cbreak mode). 3212468Swnj */ 32213Sbill if (tp->t_flags&RAW) 3232468Swnj c = 0; 32413Sbill else 3259549Ssam c = tp->t_intrc; 3262730Swnj #if NBK > 0 327139Sbill if (tp->t_line == NETLDISC) { 328117Sbill c &= 0177; 329168Sbill BKINPUT(c, tp); 330117Sbill } else 3312730Swnj #endif 3322468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 33313Sbill } 33413Sbill } 33513Sbill 33613Sbill /* 3372468Swnj * Ioctl for DH11. 33813Sbill */ 33913Sbill /*ARGSUSED*/ 3407629Ssam dhioctl(dev, cmd, data, flag) 3417629Ssam caddr_t data; 34213Sbill { 34313Sbill register struct tty *tp; 3448566Sroot register int unit = minor(dev); 3458566Sroot int error; 34613Sbill 3472395Swnj tp = &dh11[unit]; 3488566Sroot error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 3498566Sroot if (error >= 0) 3508566Sroot return (error); 3518566Sroot error = ttioctl(tp, cmd, data, flag); 3528566Sroot if (error >= 0) { 35317561Sbloom if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 35417561Sbloom cmd == TIOCLBIC || cmd == TIOCLSET) 3552395Swnj dhparam(unit); 3568566Sroot return (error); 3578566Sroot } 3588566Sroot switch (cmd) { 3597629Ssam 360168Sbill case TIOCSBRK: 3612479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 362168Sbill break; 3637629Ssam 364168Sbill case TIOCCBRK: 3652479Swnj ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 366168Sbill break; 3677629Ssam 368168Sbill case TIOCSDTR: 3692479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIS); 370168Sbill break; 3717629Ssam 372168Sbill case TIOCCDTR: 3732479Swnj dmctl(unit, DML_DTR|DML_RTS, DMBIC); 374168Sbill break; 3757629Ssam 376168Sbill default: 3778566Sroot return (ENOTTY); 378168Sbill } 3798566Sroot return (0); 38013Sbill } 38113Sbill 38213Sbill /* 38313Sbill * Set parameters from open or stty into the DH hardware 38413Sbill * registers. 38513Sbill */ 3862395Swnj dhparam(unit) 3872395Swnj register int unit; 38813Sbill { 38913Sbill register struct tty *tp; 3902479Swnj register struct dhdevice *addr; 3912395Swnj register int lpar; 392300Sbill int s; 39313Sbill 3942395Swnj tp = &dh11[unit]; 3952479Swnj addr = (struct dhdevice *)tp->t_addr; 3962468Swnj /* 3972468Swnj * Block interrupts so parameters will be set 3982468Swnj * before the line interrupts. 3992468Swnj */ 400300Sbill s = spl5(); 4012468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 40213Sbill if ((tp->t_ispeed)==0) { 4035406Swnj tp->t_state |= TS_HUPCLS; 4042479Swnj dmctl(unit, DML_OFF, DMSET); 40513Sbill return; 40613Sbill } 4072395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 4082468Swnj if ((tp->t_ispeed) == B134) 4092395Swnj lpar |= BITS6|PENABLE|HDUPLX; 41024269Slepreau else if (tp->t_flags & (RAW|LITOUT|PASS8)) 4112395Swnj lpar |= BITS8; 41213Sbill else 4132395Swnj lpar |= BITS7|PENABLE; 41413Sbill if ((tp->t_flags&EVENP) == 0) 4152395Swnj lpar |= OPAR; 4162468Swnj if ((tp->t_ospeed) == B110) 4172395Swnj lpar |= TWOSB; 4182395Swnj addr->dhlpr = lpar; 419300Sbill splx(s); 42013Sbill } 42113Sbill 42213Sbill /* 42313Sbill * DH11 transmitter interrupt. 42413Sbill * Restart each line which used to be active but has 42513Sbill * terminated transmission since the last interrupt. 42613Sbill */ 4272395Swnj dhxint(dh) 4282395Swnj int dh; 42913Sbill { 43013Sbill register struct tty *tp; 4312479Swnj register struct dhdevice *addr; 43213Sbill short ttybit, bar, *sbar; 4332974Swnj register struct uba_device *ui; 4342468Swnj register int unit; 4352605Swnj u_short cntr; 43613Sbill 4372395Swnj ui = dhinfo[dh]; 4382479Swnj addr = (struct dhdevice *)ui->ui_addr; 4392456Swnj if (addr->un.dhcsr & DH_NXM) { 4402456Swnj addr->un.dhcsr |= DH_CNI; 4412924Swnj printf("dh%d: NXM\n", dh); 442105Sbill } 4432395Swnj sbar = &dhsar[dh]; 44413Sbill bar = *sbar & ~addr->dhbar; 4452395Swnj unit = dh * 16; ttybit = 1; 4462468Swnj addr->un.dhcsr &= (short)~DH_TI; 4472468Swnj for (; bar; unit++, ttybit <<= 1) { 4482468Swnj if (bar & ttybit) { 44913Sbill *sbar &= ~ttybit; 45013Sbill bar &= ~ttybit; 4512395Swnj tp = &dh11[unit]; 4525406Swnj tp->t_state &= ~TS_BUSY; 4535406Swnj if (tp->t_state&TS_FLUSH) 4545406Swnj tp->t_state &= ~TS_FLUSH; 455113Sbill else { 4562456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4572468Swnj /* 4582468Swnj * Do arithmetic in a short to make up 4592468Swnj * for lost 16&17 bits. 4602468Swnj */ 4612605Swnj cntr = addr->dhcar - 4622468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 4633101Swnj ndflush(&tp->t_outq, (int)cntr); 464113Sbill } 465113Sbill if (tp->t_line) 46613Sbill (*linesw[tp->t_line].l_start)(tp); 467113Sbill else 46813Sbill dhstart(tp); 46913Sbill } 47013Sbill } 47113Sbill } 47213Sbill 47313Sbill /* 47413Sbill * Start (restart) transmission on the given DH11 line. 47513Sbill */ 47613Sbill dhstart(tp) 4772395Swnj register struct tty *tp; 47813Sbill { 4792479Swnj register struct dhdevice *addr; 4802468Swnj register int car, dh, unit, nch; 4812395Swnj int s; 48213Sbill 4832468Swnj unit = minor(tp->t_dev); 4842468Swnj dh = unit >> 4; 4852468Swnj unit &= 0xf; 4862479Swnj addr = (struct dhdevice *)tp->t_addr; 4872468Swnj 48813Sbill /* 4892468Swnj * Must hold interrupts in following code to prevent 4902468Swnj * state of the tp from changing. 49113Sbill */ 49213Sbill s = spl5(); 4932468Swnj /* 4942468Swnj * If it's currently active, or delaying, no need to do anything. 4952468Swnj */ 4965406Swnj if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 49713Sbill goto out; 4982468Swnj /* 4992468Swnj * If there are sleepers, and output has drained below low 5002468Swnj * water mark, wake up the sleepers. 5012468Swnj */ 5025406Swnj if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 5035406Swnj if (tp->t_state&TS_ASLEEP) { 5045406Swnj tp->t_state &= ~TS_ASLEEP; 5055406Swnj wakeup((caddr_t)&tp->t_outq); 5065406Swnj } 5075406Swnj if (tp->t_wsel) { 5085406Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 5095406Swnj tp->t_wsel = 0; 5105406Swnj tp->t_state &= ~TS_WCOLL; 5115406Swnj } 51213Sbill } 5132468Swnj /* 5142468Swnj * Now restart transmission unless the output queue is 5152468Swnj * empty. 5162468Swnj */ 51713Sbill if (tp->t_outq.c_cc == 0) 51813Sbill goto out; 5199549Ssam if (tp->t_flags & (RAW|LITOUT)) 52013Sbill nch = ndqb(&tp->t_outq, 0); 5212395Swnj else { 52213Sbill nch = ndqb(&tp->t_outq, 0200); 5232468Swnj /* 5242468Swnj * If first thing on queue is a delay process it. 5252468Swnj */ 52613Sbill if (nch == 0) { 52713Sbill nch = getc(&tp->t_outq); 5282468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 5295406Swnj tp->t_state |= TS_TIMEOUT; 53013Sbill goto out; 53113Sbill } 53213Sbill } 5332468Swnj /* 5342468Swnj * If characters to transmit, restart transmission. 5352468Swnj */ 53613Sbill if (nch) { 5372468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 5382468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 5393586Sroot /* 5403586Sroot * The following nonsense with short word 5413586Sroot * is to make sure the dhbar |= word below 5423586Sroot * is done with an interlocking bisw2 instruction. 5433586Sroot */ 5443586Sroot { short word = 1 << unit; 5453586Sroot dhsar[dh] |= word; 5462468Swnj addr->dhcar = car; 54713Sbill addr->dhbcr = -nch; 5483586Sroot addr->dhbar |= word; 5493586Sroot } 5505406Swnj tp->t_state |= TS_BUSY; 55113Sbill } 5522395Swnj out: 55313Sbill splx(s); 55413Sbill } 55513Sbill 55613Sbill /* 5572468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 55813Sbill */ 55913Sbill /*ARGSUSED*/ 56013Sbill dhstop(tp, flag) 5612468Swnj register struct tty *tp; 56213Sbill { 5632479Swnj register struct dhdevice *addr; 5642395Swnj register int unit, s; 56513Sbill 5662479Swnj addr = (struct dhdevice *)tp->t_addr; 5672468Swnj /* 5682468Swnj * Block input/output interrupts while messing with state. 5692468Swnj */ 5702468Swnj s = spl5(); 5715406Swnj if (tp->t_state & TS_BUSY) { 5722468Swnj /* 5732468Swnj * Device is transmitting; stop output 5742468Swnj * by selecting the line and setting the byte 5752468Swnj * count to -1. We will clean up later 5762468Swnj * by examining the address where the dh stopped. 5772468Swnj */ 5782395Swnj unit = minor(tp->t_dev); 5792456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 5805406Swnj if ((tp->t_state&TS_TTSTOP)==0) 5815406Swnj tp->t_state |= TS_FLUSH; 582113Sbill addr->dhbcr = -1; 583113Sbill } 58413Sbill splx(s); 58513Sbill } 58613Sbill 587168Sbill /* 588280Sbill * Reset state of driver if UBA reset was necessary. 589280Sbill * Reset the csrl and lpr registers on open lines, and 590280Sbill * restart transmitters. 591280Sbill */ 5922395Swnj dhreset(uban) 5932468Swnj int uban; 594280Sbill { 5952395Swnj register int dh, unit; 596280Sbill register struct tty *tp; 5972974Swnj register struct uba_device *ui; 5982421Skre int i; 599280Sbill 6002421Skre if (dh_ubinfo[uban] == 0) 6012421Skre return; 6022421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 6032770Swnj 512+nclist*sizeof (struct cblock), 0); 6042421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 6052395Swnj dh = 0; 6062643Swnj for (dh = 0; dh < NDH; dh++) { 6072421Skre ui = dhinfo[dh]; 6082421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 6092421Skre continue; 6102924Swnj printf(" dh%d", dh); 6112479Swnj ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; 61216190Skarels ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; 6132421Skre unit = dh * 16; 6142421Skre for (i = 0; i < 16; i++) { 6152421Skre tp = &dh11[unit]; 6165406Swnj if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 6172421Skre dhparam(unit); 6182479Swnj dmctl(unit, DML_ON, DMSET); 6195406Swnj tp->t_state &= ~TS_BUSY; 6202421Skre dhstart(tp); 6212421Skre } 6222421Skre unit++; 623300Sbill } 624300Sbill } 62516190Skarels dhsilos = 0; 626280Sbill } 6272395Swnj 62816190Skarels int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 6292468Swnj /* 63016190Skarels * At software clock interrupt time, check status. 63116190Skarels * Empty all the dh silos that are in use, and decide whether 63216190Skarels * to turn any silos off or on. 6332468Swnj */ 6342456Swnj dhtimer() 6352456Swnj { 63616190Skarels register int dh, s; 63716190Skarels static int timercalls; 6382456Swnj 63916190Skarels if (dhsilos) { 64016190Skarels dhfasttimers++; /*DEBUG*/ 64116190Skarels timercalls++; 64216190Skarels s = spl5(); 64316190Skarels for (dh = 0; dh < NDH; dh++) 64416190Skarels if (dhsilos & (1 << dh)) 64516190Skarels dhrint(dh); 64616190Skarels splx(s); 64716190Skarels } 64816190Skarels if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 64916190Skarels dhslowtimers++; /*DEBUG*/ 65016190Skarels timercalls = 0; 65116190Skarels for (dh = 0; dh < NDH; dh++) { 65216190Skarels ave(dhrate[dh], dhchars[dh], 8); 65316190Skarels if ((dhchars[dh] > dhhighrate) && 65416190Skarels ((dhsilos & (1 << dh)) == 0)) { 65516190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 65616190Skarels (dhchars[dh] > 500? 32 : 16); 65716190Skarels dhsilos |= (1 << dh); 65816190Skarels dhtransitions++; /*DEBUG*/ 65916190Skarels } else if ((dhsilos & (1 << dh)) && 66016190Skarels (dhrate[dh] < dhlowrate)) { 66116190Skarels ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; 66216190Skarels dhsilos &= ~(1 << dh); 66316190Skarels } 66416190Skarels dhchars[dh] = 0; 66516190Skarels } 66616190Skarels } 66716190Skarels timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); 6682456Swnj } 6692456Swnj 6702468Swnj /* 6712479Swnj * Turn on the line associated with dh dev. 6722468Swnj */ 6732468Swnj dmopen(dev) 6742468Swnj dev_t dev; 6752468Swnj { 6762468Swnj register struct tty *tp; 6772468Swnj register struct dmdevice *addr; 6782974Swnj register struct uba_device *ui; 6792468Swnj register int unit; 6802468Swnj register int dm; 6813792Swnj int s; 6822468Swnj 6832468Swnj unit = minor(dev); 6842479Swnj dm = unit >> 4; 6852468Swnj tp = &dh11[unit]; 6862566Swnj unit &= 0xf; 68716942Skarels if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 6885406Swnj tp->t_state |= TS_CARR_ON; 6892468Swnj return; 6902468Swnj } 6912468Swnj addr = (struct dmdevice *)ui->ui_addr; 6923792Swnj s = spl5(); 6932479Swnj addr->dmcsr &= ~DM_SE; 6942479Swnj while (addr->dmcsr & DM_BUSY) 6952468Swnj ; 6962566Swnj addr->dmcsr = unit; 6972479Swnj addr->dmlstat = DML_ON; 69816942Skarels if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit))) 6995406Swnj tp->t_state |= TS_CARR_ON; 7003792Swnj addr->dmcsr = DM_IE|DM_SE; 7015406Swnj while ((tp->t_state&TS_CARR_ON)==0) 7022468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 7033792Swnj splx(s); 7042468Swnj } 7052468Swnj 7062468Swnj /* 7072468Swnj * Dump control bits into the DM registers. 7082468Swnj */ 7092468Swnj dmctl(dev, bits, how) 7102468Swnj dev_t dev; 7112468Swnj int bits, how; 7122468Swnj { 7132974Swnj register struct uba_device *ui; 7142468Swnj register struct dmdevice *addr; 7152468Swnj register int unit, s; 7162468Swnj int dm; 7172468Swnj 7182468Swnj unit = minor(dev); 7192468Swnj dm = unit >> 4; 7202468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 7212468Swnj return; 7222468Swnj addr = (struct dmdevice *)ui->ui_addr; 7232468Swnj s = spl5(); 7242479Swnj addr->dmcsr &= ~DM_SE; 7252479Swnj while (addr->dmcsr & DM_BUSY) 7262468Swnj ; 7272468Swnj addr->dmcsr = unit & 0xf; 7282468Swnj switch(how) { 7292468Swnj case DMSET: 7302468Swnj addr->dmlstat = bits; 7312468Swnj break; 7322468Swnj case DMBIS: 7332468Swnj addr->dmlstat |= bits; 7342468Swnj break; 7352468Swnj case DMBIC: 7362468Swnj addr->dmlstat &= ~bits; 7372468Swnj break; 7382468Swnj } 7393792Swnj addr->dmcsr = DM_IE|DM_SE; 7402468Swnj splx(s); 7412468Swnj } 7422468Swnj 7432468Swnj /* 7442468Swnj * DM11 interrupt; deal with carrier transitions. 7452468Swnj */ 7462468Swnj dmintr(dm) 7472468Swnj register int dm; 7482468Swnj { 7492974Swnj register struct uba_device *ui; 7502468Swnj register struct tty *tp; 7512468Swnj register struct dmdevice *addr; 75216942Skarels int unit; 7532468Swnj 7542468Swnj ui = dminfo[dm]; 7552479Swnj if (ui == 0) 7562479Swnj return; 7572468Swnj addr = (struct dmdevice *)ui->ui_addr; 7583997Sroot if (addr->dmcsr&DM_DONE) { 7593997Sroot if (addr->dmcsr&DM_CF) { 76016942Skarels unit = addr->dmcsr & 0xf; 76116942Skarels tp = &dh11[(dm << 4) + unit]; 7623997Sroot wakeup((caddr_t)&tp->t_rawq); 7639549Ssam if ((tp->t_state&TS_WOPEN) == 0 && 7649605Ssam (tp->t_flags & MDMBUF)) { 7653997Sroot if (addr->dmlstat & DML_CAR) { 7665406Swnj tp->t_state &= ~TS_TTSTOP; 7673997Sroot ttstart(tp); 7685406Swnj } else if ((tp->t_state&TS_TTSTOP) == 0) { 7695406Swnj tp->t_state |= TS_TTSTOP; 7703997Sroot dhstop(tp, 0); 7713997Sroot } 77221954Skarels } else if ((addr->dmlstat & DML_CAR)==0) { 77321954Skarels if ((tp->t_state & TS_CARR_ON) && 77416942Skarels (tp->t_flags & NOHANG) == 0 && 77516942Skarels (dhsoftCAR[dm] & (1<<unit)) == 0) { 77621954Skarels if (tp->t_state & TS_ISOPEN) { 77721954Skarels gsignal(tp->t_pgrp, SIGHUP); 77821954Skarels gsignal(tp->t_pgrp, SIGCONT); 77921954Skarels addr->dmlstat = 0; 78021954Skarels ttyflush(tp, FREAD|FWRITE); 78121954Skarels } 78221954Skarels tp->t_state &= ~TS_CARR_ON; 7833997Sroot } 7843997Sroot } else 7855406Swnj tp->t_state |= TS_CARR_ON; 7863997Sroot } 7873997Sroot addr->dmcsr = DM_IE|DM_SE; 7882468Swnj } 7892468Swnj } 7902625Swnj #endif 791