123322Smckusick /* 229211Smckusick * Copyright (c) 1985, 1986 Regents of the University of California. 323322Smckusick * All rights reserved. The Berkeley software License Agreement 423322Smckusick * specifies the terms and conditions for redistribution. 523322Smckusick * 6*36610Sbostic * @(#)dhu.c 7.4 (Berkeley) 01/24/89 723322Smckusick */ 820976Smckusick 920976Smckusick /* 1020976Smckusick * based on dh.c 6.3 84/03/15 1120976Smckusick * and on dmf.c 6.2 84/02/16 1220976Smckusick * 1320976Smckusick * Dave Johnson, Brown University Computer Science 1420976Smckusick * ddj%brown@csnet-relay 1520976Smckusick */ 1620976Smckusick 1720976Smckusick #include "dhu.h" 1820976Smckusick #if NDHU > 0 1920976Smckusick /* 2020976Smckusick * DHU-11 driver 2120976Smckusick */ 2220976Smckusick #include "../machine/pte.h" 2320976Smckusick 2420976Smckusick #include "bk.h" 2520976Smckusick #include "param.h" 2620976Smckusick #include "conf.h" 2720976Smckusick #include "dir.h" 2820976Smckusick #include "user.h" 2920976Smckusick #include "proc.h" 3020976Smckusick #include "ioctl.h" 3120976Smckusick #include "tty.h" 3220976Smckusick #include "map.h" 3320976Smckusick #include "buf.h" 3420976Smckusick #include "vm.h" 3520976Smckusick #include "kernel.h" 3620976Smckusick #include "syslog.h" 3720976Smckusick 3820976Smckusick #include "uba.h" 3920976Smckusick #include "ubareg.h" 4020976Smckusick #include "ubavar.h" 4120976Smckusick #include "dhureg.h" 4220976Smckusick 4320976Smckusick #include "bkmac.h" 4420976Smckusick #include "clist.h" 4520976Smckusick #include "file.h" 4620976Smckusick #include "uio.h" 4720976Smckusick 4820976Smckusick /* 4920976Smckusick * Definition of the driver for the auto-configuration program. 5020976Smckusick */ 5120976Smckusick int dhuprobe(), dhuattach(), dhurint(), dhuxint(); 5220976Smckusick struct uba_device *dhuinfo[NDHU]; 5325519Stef u_short dhustd[] = { 160440, 160500, 0 }; /* some common addresses */ 5420976Smckusick struct uba_driver dhudriver = 5520976Smckusick { dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo }; 5620976Smckusick 5720976Smckusick #define NDHULINE (NDHU*16) 5820976Smckusick 5920976Smckusick #define UNIT(x) (minor(x)) 6020976Smckusick 6120976Smckusick #ifndef PORTSELECTOR 6225395Skarels #define ISPEED B9600 6320976Smckusick #define IFLAGS (EVENP|ODDP|ECHO) 6420976Smckusick #else 6520976Smckusick #define ISPEED B4800 6620976Smckusick #define IFLAGS (EVENP|ODDP) 6720976Smckusick #endif 6820976Smckusick 6920976Smckusick /* 7020976Smckusick * default receive silo timeout value -- valid values are 2..255 7120976Smckusick * number of ms. to delay between first char received and receive interrupt 7220976Smckusick * 7320976Smckusick * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0 7420976Smckusick */ 7520976Smckusick #define DHU_DEF_TIMO 20 7620976Smckusick 7720976Smckusick /* 7820976Smckusick * Other values for silo timeout register defined here but not used: 7920976Smckusick * receive interrupt only on modem control or silo alarm (3/4 full) 8020976Smckusick */ 8120976Smckusick #define DHU_POLL_TIMO 0 8220976Smckusick /* 8320976Smckusick * receive interrupt immediately on receive character 8420976Smckusick */ 8520976Smckusick #define DHU_NO_TIMO 1 8620976Smckusick 8720976Smckusick /* 8820976Smckusick * Local variables for the driver 8920976Smckusick */ 9020976Smckusick /* 9120976Smckusick * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B". 9220976Smckusick * EXTA => 19200 baud 9320976Smckusick * EXTB => 2000 baud 9420976Smckusick */ 9520976Smckusick char dhu_speeds[] = 9620976Smckusick { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 10, 11, 13, 14, 9 }; 9720976Smckusick 9820976Smckusick short dhusoftCAR[NDHU]; 9920976Smckusick 10020976Smckusick struct tty dhu_tty[NDHULINE]; 10120976Smckusick int ndhu = NDHULINE; 10220976Smckusick int dhuact; /* mask of active dhu's */ 10320976Smckusick int dhustart(), ttrstrt(); 10420976Smckusick 10520976Smckusick /* 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. 10920976Smckusick * The UBACVT macro converts a clist space address for unibus uban 11020976Smckusick * into an i/o space address for the DMA routine. 11120976Smckusick */ 11230322Skarels int dhu_uballoc[NUBA]; /* which dhu (if any) allocated unibus map */ 11330322Skarels int cbase[NUBA]; /* base address of clists in unibus map */ 11420976Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 11520976Smckusick 11620976Smckusick /* 11720976Smckusick * Routine for configuration to force a dhu to interrupt. 11820976Smckusick */ 11920976Smckusick /*ARGSUSED*/ 12020976Smckusick dhuprobe(reg) 12120976Smckusick caddr_t reg; 12220976Smckusick { 12320976Smckusick register int br, cvec; /* these are ``value-result'' */ 12420976Smckusick register struct dhudevice *dhuaddr = (struct dhudevice *)reg; 12520976Smckusick int i; 12620976Smckusick 12720976Smckusick #ifdef lint 12820976Smckusick br = 0; cvec = br; br = cvec; 12920976Smckusick if (ndhu == 0) ndhu = 1; 13020976Smckusick dhurint(0); dhuxint(0); 13120976Smckusick #endif 13220976Smckusick /* 13320976Smckusick * The basic idea here is: 13420976Smckusick * do a self-test by setting the Master-Reset bit 13520976Smckusick * if this fails, then return 13620976Smckusick * if successful, there will be 8 diagnostic codes in RX FIFO 13720976Smckusick * therefore ask for a Received-Data-Available interrupt 13820976Smckusick * wait for it... 13920976Smckusick * reset the interrupt-enable bit and flush out the diag. codes 14020976Smckusick */ 14120976Smckusick dhuaddr->dhucsr = DHU_CS_MCLR; 14220976Smckusick for (i = 0; i < 1000; i++) { 14320976Smckusick DELAY(10000); 14420976Smckusick if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0) 14520976Smckusick break; 14620976Smckusick } 14720976Smckusick if (dhuaddr->dhucsr&DHU_CS_MCLR) 14820976Smckusick return(0); 14920976Smckusick if (dhuaddr->dhucsr&DHU_CS_DFAIL) 15020976Smckusick return(0); 15120976Smckusick dhuaddr->dhucsr = DHU_CS_RIE; 15220976Smckusick DELAY(1000); 15320976Smckusick dhuaddr->dhucsr = 0; 15420976Smckusick while (dhuaddr->dhurbuf < 0) 15520976Smckusick /* void */; 15620976Smckusick return (sizeof(struct dhudevice)); 15720976Smckusick } 15820976Smckusick 15920976Smckusick /* 16020976Smckusick * Routine called to attach a dhu. 16120976Smckusick */ 16220976Smckusick dhuattach(ui) 16320976Smckusick struct uba_device *ui; 16420976Smckusick { 16520976Smckusick 16620976Smckusick dhusoftCAR[ui->ui_unit] = ui->ui_flags; 16726220Skarels cbase[ui->ui_ubanum] = -1; 168*36610Sbostic dhu_uballoc[ui->ui_ubanum] = -1; 16920976Smckusick } 17020976Smckusick 17120976Smckusick /* 17220976Smckusick * Open a DHU11 line, mapping the clist onto the uba if this 17320976Smckusick * is the first dhu on this uba. Turn on this dhu if this is 17420976Smckusick * the first use of it. 17520976Smckusick */ 17620976Smckusick /*ARGSUSED*/ 17720976Smckusick dhuopen(dev, flag) 17820976Smckusick dev_t dev; 17920976Smckusick { 18020976Smckusick register struct tty *tp; 18120976Smckusick register int unit, dhu; 18220976Smckusick register struct dhudevice *addr; 18320976Smckusick register struct uba_device *ui; 18420976Smckusick int s; 18520976Smckusick 18620976Smckusick unit = UNIT(dev); 18720976Smckusick dhu = unit >> 4; 18820976Smckusick if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0) 18920976Smckusick return (ENXIO); 19020976Smckusick tp = &dhu_tty[unit]; 19120976Smckusick if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 19220976Smckusick return (EBUSY); 19320976Smckusick addr = (struct dhudevice *)ui->ui_addr; 19420976Smckusick tp->t_addr = (caddr_t)addr; 19520976Smckusick tp->t_oproc = dhustart; 19620976Smckusick /* 19720976Smckusick * While setting up state for this uba and this dhu, 19820976Smckusick * block uba resets which can clear the state. 19920976Smckusick */ 20020976Smckusick s = spl5(); 20126220Skarels if (cbase[ui->ui_ubanum] == -1) { 20230322Skarels dhu_uballoc[ui->ui_ubanum] = dhu; 20330322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, 20430322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); 20520976Smckusick } 20620976Smckusick if ((dhuact&(1<<dhu)) == 0) { 20720976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 20820976Smckusick addr->dhutimo = DHU_DEF_TIMO; 20920976Smckusick dhuact |= (1<<dhu); 21020976Smckusick /* anything else to configure whole board */ 21120976Smckusick } 21220976Smckusick (void) splx(s); 21320976Smckusick /* 21420976Smckusick * If this is first open, initialize tty state to default. 21520976Smckusick */ 21620976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 21720976Smckusick ttychars(tp); 21820976Smckusick #ifndef PORTSELECTOR 21920976Smckusick if (tp->t_ispeed == 0) { 22020976Smckusick #else 22120976Smckusick tp->t_state |= TS_HUPCLS; 22220976Smckusick #endif PORTSELECTOR 22320976Smckusick tp->t_ispeed = ISPEED; 22420976Smckusick tp->t_ospeed = ISPEED; 22520976Smckusick tp->t_flags = IFLAGS; 22620976Smckusick #ifndef PORTSELECTOR 22720976Smckusick } 22820976Smckusick #endif PORTSELECTOR 22920976Smckusick tp->t_dev = dev; 23020976Smckusick dhuparam(unit); 23120976Smckusick } 23220976Smckusick /* 23320976Smckusick * Wait for carrier, then process line discipline specific open. 23420976Smckusick */ 23520976Smckusick s = spl5(); 23620976Smckusick if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 23720976Smckusick (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 23820976Smckusick tp->t_state |= TS_CARR_ON; 23920976Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 24020976Smckusick tp->t_state |= TS_WOPEN; 24120976Smckusick sleep((caddr_t)&tp->t_rawq, TTIPRI); 24220976Smckusick } 24320976Smckusick (void) splx(s); 24420976Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp)); 24520976Smckusick } 24620976Smckusick 24720976Smckusick /* 24820976Smckusick * Close a DHU11 line, turning off the modem control. 24920976Smckusick */ 25020976Smckusick /*ARGSUSED*/ 25120976Smckusick dhuclose(dev, flag) 25220976Smckusick dev_t dev; 25320976Smckusick int flag; 25420976Smckusick { 25520976Smckusick register struct tty *tp; 25620976Smckusick register unit; 25720976Smckusick 25820976Smckusick unit = UNIT(dev); 25920976Smckusick tp = &dhu_tty[unit]; 26020976Smckusick (*linesw[tp->t_line].l_close)(tp); 26120976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 26220976Smckusick if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0) 26320976Smckusick #ifdef PORTSELECTOR 26420976Smckusick { 26520976Smckusick extern int wakeup(); 26620976Smckusick 26720976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 26820976Smckusick /* Hold DTR low for 0.5 seconds */ 26920976Smckusick timeout(wakeup, (caddr_t) &tp->t_dev, hz/2); 27020976Smckusick sleep((caddr_t) &tp->t_dev, PZERO); 27120976Smckusick } 27220976Smckusick #else 27320976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 27420976Smckusick #endif PORTSELECTOR 27520976Smckusick ttyclose(tp); 27620976Smckusick } 27720976Smckusick 27820976Smckusick dhuread(dev, uio) 27920976Smckusick dev_t dev; 28020976Smckusick struct uio *uio; 28120976Smckusick { 28220976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 28320976Smckusick 28420976Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio)); 28520976Smckusick } 28620976Smckusick 28720976Smckusick dhuwrite(dev, uio) 28820976Smckusick dev_t dev; 28920976Smckusick struct uio *uio; 29020976Smckusick { 29120976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 29220976Smckusick 29320976Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio)); 29420976Smckusick } 29520976Smckusick 29620976Smckusick /* 29720976Smckusick * DHU11 receiver interrupt. 29820976Smckusick */ 29920976Smckusick dhurint(dhu) 30020976Smckusick int dhu; 30120976Smckusick { 30220976Smckusick register struct tty *tp; 30320976Smckusick register c; 30420976Smckusick register struct dhudevice *addr; 30520976Smckusick register struct tty *tp0; 30620976Smckusick register struct uba_device *ui; 30720976Smckusick register line; 30820976Smckusick int overrun = 0; 30920976Smckusick 31035401Stef #ifdef QBA 31127256Skridle (void) spl5(); 31227256Skridle #endif 31320976Smckusick ui = dhuinfo[dhu]; 31420976Smckusick if (ui == 0 || ui->ui_alive == 0) 31520976Smckusick return; 31620976Smckusick addr = (struct dhudevice *)ui->ui_addr; 31720976Smckusick tp0 = &dhu_tty[dhu<<4]; 31820976Smckusick /* 31920976Smckusick * Loop fetching characters from the silo for this 32020976Smckusick * dhu until there are no more in the silo. 32120976Smckusick */ 32220976Smckusick while ((c = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 32320976Smckusick line = DHU_RX_LINE(c); 32420976Smckusick tp = tp0 + line; 32520976Smckusick if ((c & DHU_RB_STAT) == DHU_RB_STAT) { 32620976Smckusick /* 32720976Smckusick * modem changed or diag info 32820976Smckusick */ 32920976Smckusick if (c & DHU_RB_DIAG) { 33020976Smckusick /* decode diagnostic messages */ 33120976Smckusick continue; 33220976Smckusick } 33325395Skarels if (c & DHU_ST_DCD) 33425395Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 33525395Skarels else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 33625395Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 33725395Skarels (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 33820976Smckusick continue; 33920976Smckusick } 34020976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 34120976Smckusick wakeup((caddr_t)&tp->t_rawq); 34220976Smckusick #ifdef PORTSELECTOR 34320976Smckusick if ((tp->t_state&TS_WOPEN) == 0) 34420976Smckusick #endif 34525395Skarels continue; 34620976Smckusick } 34720976Smckusick if (c & DHU_RB_PE) 34820976Smckusick if ((tp->t_flags&(EVENP|ODDP)) == EVENP || 34920976Smckusick (tp->t_flags&(EVENP|ODDP)) == ODDP) 35020976Smckusick continue; 35120976Smckusick if ((c & DHU_RB_DO) && overrun == 0) { 35224841Seric log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 35320976Smckusick overrun = 1; 35420976Smckusick } 35520976Smckusick if (c & DHU_RB_FE) 35620976Smckusick /* 35720976Smckusick * At framing error (break) generate 35820976Smckusick * a null (in raw mode, for getty), or a 35920976Smckusick * interrupt (in cooked/cbreak mode). 36020976Smckusick */ 36120976Smckusick if (tp->t_flags&RAW) 36220976Smckusick c = 0; 36320976Smckusick else 36420976Smckusick c = tp->t_intrc; 36520976Smckusick #if NBK > 0 36620976Smckusick if (tp->t_line == NETLDISC) { 36720976Smckusick c &= 0x7f; 36820976Smckusick BKINPUT(c, tp); 36920976Smckusick } else 37020976Smckusick #endif 37120976Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 37220976Smckusick } 37320976Smckusick } 37420976Smckusick 37520976Smckusick /* 37620976Smckusick * Ioctl for DHU11. 37720976Smckusick */ 37820976Smckusick /*ARGSUSED*/ 37920976Smckusick dhuioctl(dev, cmd, data, flag) 38020976Smckusick caddr_t data; 38120976Smckusick { 38220976Smckusick register struct tty *tp; 38320976Smckusick register int unit = UNIT(dev); 38420976Smckusick int error; 38520976Smckusick 38620976Smckusick tp = &dhu_tty[unit]; 38720976Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 38820976Smckusick if (error >= 0) 38920976Smckusick return (error); 39020976Smckusick error = ttioctl(tp, cmd, data, flag); 39120976Smckusick if (error >= 0) { 39220976Smckusick if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET || 39320976Smckusick cmd == TIOCLBIC || cmd == TIOCLBIS) 39420976Smckusick dhuparam(unit); 39520976Smckusick return (error); 39620976Smckusick } 39720976Smckusick 39820976Smckusick switch (cmd) { 39920976Smckusick case TIOCSBRK: 40020976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIS); 40120976Smckusick break; 40220976Smckusick 40320976Smckusick case TIOCCBRK: 40420976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 40520976Smckusick break; 40620976Smckusick 40720976Smckusick case TIOCSDTR: 40820976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 40920976Smckusick break; 41020976Smckusick 41120976Smckusick case TIOCCDTR: 41220976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 41320976Smckusick break; 41420976Smckusick 41520976Smckusick case TIOCMSET: 41620976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 41720976Smckusick break; 41820976Smckusick 41920976Smckusick case TIOCMBIS: 42020976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 42120976Smckusick break; 42220976Smckusick 42320976Smckusick case TIOCMBIC: 42420976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 42520976Smckusick break; 42620976Smckusick 42720976Smckusick case TIOCMGET: 42820976Smckusick *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 42920976Smckusick break; 43020976Smckusick default: 43120976Smckusick return (ENOTTY); 43220976Smckusick } 43320976Smckusick return (0); 43420976Smckusick } 43520976Smckusick 43620976Smckusick dmtodhu(bits) 43720976Smckusick register int bits; 43820976Smckusick { 43920976Smckusick register int b = 0; 44020976Smckusick 44120976Smckusick if (bits & DML_RTS) b |= DHU_RTS; 44220976Smckusick if (bits & DML_DTR) b |= DHU_DTR; 44320976Smckusick if (bits & DML_LE) b |= DHU_LE; 44420976Smckusick return(b); 44520976Smckusick } 44620976Smckusick 44720976Smckusick dhutodm(bits) 44820976Smckusick register int bits; 44920976Smckusick { 45020976Smckusick register int b = 0; 45120976Smckusick 45220976Smckusick if (bits & DHU_DSR) b |= DML_DSR; 45320976Smckusick if (bits & DHU_RNG) b |= DML_RNG; 45420976Smckusick if (bits & DHU_CAR) b |= DML_CAR; 45520976Smckusick if (bits & DHU_CTS) b |= DML_CTS; 45620976Smckusick if (bits & DHU_RTS) b |= DML_RTS; 45720976Smckusick if (bits & DHU_DTR) b |= DML_DTR; 45820976Smckusick if (bits & DHU_LE) b |= DML_LE; 45920976Smckusick return(b); 46020976Smckusick } 46120976Smckusick 46220976Smckusick 46320976Smckusick /* 46420976Smckusick * Set parameters from open or stty into the DHU hardware 46520976Smckusick * registers. 46620976Smckusick */ 46720976Smckusick dhuparam(unit) 46820976Smckusick register int unit; 46920976Smckusick { 47020976Smckusick register struct tty *tp; 47120976Smckusick register struct dhudevice *addr; 47220976Smckusick register int lpar; 47320976Smckusick int s; 47420976Smckusick 47520976Smckusick tp = &dhu_tty[unit]; 47620976Smckusick addr = (struct dhudevice *)tp->t_addr; 47720976Smckusick /* 47820976Smckusick * Block interrupts so parameters will be set 47920976Smckusick * before the line interrupts. 48020976Smckusick */ 48120976Smckusick s = spl5(); 48220976Smckusick if ((tp->t_ispeed) == 0) { 48320976Smckusick tp->t_state |= TS_HUPCLS; 48420976Smckusick (void)dhumctl(unit, DHU_OFF, DMSET); 48520976Smckusick splx(s); 48620976Smckusick return; 48720976Smckusick } 48820976Smckusick lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8); 48920976Smckusick if ((tp->t_ispeed) == B134) 49020976Smckusick lpar |= DHU_LP_BITS6|DHU_LP_PENABLE; 49124270Slepreau else if (tp->t_flags & (RAW|LITOUT|PASS8)) 49220976Smckusick lpar |= DHU_LP_BITS8; 49320976Smckusick else 49420976Smckusick lpar |= DHU_LP_BITS7|DHU_LP_PENABLE; 49520976Smckusick if (tp->t_flags&EVENP) 49620976Smckusick lpar |= DHU_LP_EPAR; 49720976Smckusick if ((tp->t_ospeed) == B110) 49820976Smckusick lpar |= DHU_LP_TWOSB; 49920976Smckusick addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 50020976Smckusick addr->dhulpr = lpar; 50120976Smckusick splx(s); 50220976Smckusick } 50320976Smckusick 50420976Smckusick /* 50520976Smckusick * DHU11 transmitter interrupt. 50620976Smckusick * Restart each line which used to be active but has 50720976Smckusick * terminated transmission since the last interrupt. 50820976Smckusick */ 50920976Smckusick dhuxint(dhu) 51020976Smckusick int dhu; 51120976Smckusick { 51220976Smckusick register struct tty *tp; 51320976Smckusick register struct dhudevice *addr; 51420976Smckusick register struct tty *tp0; 51520976Smckusick register struct uba_device *ui; 51620976Smckusick register int line, t; 51720976Smckusick u_short cntr; 51820976Smckusick 51935401Stef #ifdef QBA 52027256Skridle (void) spl5(); 52127256Skridle #endif 52220976Smckusick ui = dhuinfo[dhu]; 52320976Smckusick tp0 = &dhu_tty[dhu<<4]; 52420976Smckusick addr = (struct dhudevice *)ui->ui_addr; 52520976Smckusick while ((t = addr->dhucsrh) & DHU_CSH_TI) { 52620976Smckusick line = DHU_TX_LINE(t); 52720976Smckusick tp = tp0 + line; 52820976Smckusick tp->t_state &= ~TS_BUSY; 52920976Smckusick if (t & DHU_CSH_NXM) { 53020976Smckusick printf("dhu(%d,%d): NXM fault\n", dhu, line); 53120976Smckusick /* SHOULD RESTART OR SOMETHING... */ 53220976Smckusick } 53320976Smckusick if (tp->t_state&TS_FLUSH) 53420976Smckusick tp->t_state &= ~TS_FLUSH; 53520976Smckusick else { 53620976Smckusick addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 53720976Smckusick /* 53820976Smckusick * Do arithmetic in a short to make up 53920976Smckusick * for lost 16&17 bits. 54020976Smckusick */ 54120976Smckusick cntr = addr->dhubar1 - 54220976Smckusick UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 54320976Smckusick ndflush(&tp->t_outq, (int)cntr); 54420976Smckusick } 54520976Smckusick if (tp->t_line) 54620976Smckusick (*linesw[tp->t_line].l_start)(tp); 54720976Smckusick else 54820976Smckusick dhustart(tp); 54920976Smckusick } 55020976Smckusick } 55120976Smckusick 55220976Smckusick /* 55320976Smckusick * Start (restart) transmission on the given DHU11 line. 55420976Smckusick */ 55520976Smckusick dhustart(tp) 55620976Smckusick register struct tty *tp; 55720976Smckusick { 55820976Smckusick register struct dhudevice *addr; 55920976Smckusick register int car, dhu, unit, nch; 56020976Smckusick int s; 56120976Smckusick 56220976Smckusick unit = minor(tp->t_dev); 56320976Smckusick dhu = unit >> 4; 56420976Smckusick unit &= 0xf; 56520976Smckusick addr = (struct dhudevice *)tp->t_addr; 56620976Smckusick 56720976Smckusick /* 56820976Smckusick * Must hold interrupts in following code to prevent 56920976Smckusick * state of the tp from changing. 57020976Smckusick */ 57120976Smckusick s = spl5(); 57220976Smckusick /* 57320976Smckusick * If it's currently active, or delaying, no need to do anything. 57420976Smckusick */ 57520976Smckusick if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 57620976Smckusick goto out; 57720976Smckusick /* 57820976Smckusick * If there are sleepers, and output has drained below low 57920976Smckusick * water mark, wake up the sleepers.. 58020976Smckusick */ 58120976Smckusick if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 58220976Smckusick if (tp->t_state&TS_ASLEEP) { 58320976Smckusick tp->t_state &= ~TS_ASLEEP; 58420976Smckusick wakeup((caddr_t)&tp->t_outq); 58520976Smckusick } 58620976Smckusick if (tp->t_wsel) { 58720976Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 58820976Smckusick tp->t_wsel = 0; 58920976Smckusick tp->t_state &= ~TS_WCOLL; 59020976Smckusick } 59120976Smckusick } 59220976Smckusick /* 59320976Smckusick * Now restart transmission unless the output queue is 59420976Smckusick * empty. 59520976Smckusick */ 59620976Smckusick if (tp->t_outq.c_cc == 0) 59720976Smckusick goto out; 59820976Smckusick if (tp->t_flags & (RAW|LITOUT)) 59920976Smckusick nch = ndqb(&tp->t_outq, 0); 60020976Smckusick else { 60120976Smckusick nch = ndqb(&tp->t_outq, 0200); 60220976Smckusick /* 60320976Smckusick * If first thing on queue is a delay process it. 60420976Smckusick */ 60520976Smckusick if (nch == 0) { 60620976Smckusick nch = getc(&tp->t_outq); 60720976Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 60820976Smckusick tp->t_state |= TS_TIMEOUT; 60920976Smckusick goto out; 61020976Smckusick } 61120976Smckusick } 61220976Smckusick /* 61320976Smckusick * If characters to transmit, restart transmission. 61420976Smckusick */ 61520976Smckusick if (nch) { 61620976Smckusick car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 61720976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 61820976Smckusick addr->dhulcr &= ~DHU_LC_TXABORT; 61920976Smckusick addr->dhubcr = nch; 62020976Smckusick addr->dhubar1 = car; 62120976Smckusick addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 62220976Smckusick DHU_BA2_DMAGO; 62320976Smckusick tp->t_state |= TS_BUSY; 62420976Smckusick } 62520976Smckusick out: 62620976Smckusick splx(s); 62720976Smckusick } 62820976Smckusick 62920976Smckusick /* 63020976Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush. 63120976Smckusick */ 63220976Smckusick /*ARGSUSED*/ 63320976Smckusick dhustop(tp, flag) 63420976Smckusick register struct tty *tp; 63520976Smckusick { 63620976Smckusick register struct dhudevice *addr; 63720976Smckusick register int unit, s; 63820976Smckusick 63920976Smckusick addr = (struct dhudevice *)tp->t_addr; 64020976Smckusick /* 64120976Smckusick * Block input/output interrupts while messing with state. 64220976Smckusick */ 64320976Smckusick s = spl5(); 64420976Smckusick if (tp->t_state & TS_BUSY) { 64520976Smckusick /* 64620976Smckusick * Device is transmitting; stop output 64720976Smckusick * by selecting the line and setting the 64820976Smckusick * abort xmit bit. We will get an xmit interrupt, 64920976Smckusick * where we will figure out where to continue the 65020976Smckusick * next time the transmitter is enabled. If 65120976Smckusick * TS_FLUSH is set, the outq will be flushed. 65220976Smckusick * In either case, dhustart will clear the TXABORT bit. 65320976Smckusick */ 65420976Smckusick unit = minor(tp->t_dev); 65520976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 65620976Smckusick addr->dhulcr |= DHU_LC_TXABORT; 65720976Smckusick if ((tp->t_state&TS_TTSTOP)==0) 65820976Smckusick tp->t_state |= TS_FLUSH; 65920976Smckusick } 66020976Smckusick (void) splx(s); 66120976Smckusick } 66220976Smckusick 66320976Smckusick /* 66420976Smckusick * DHU11 modem control 66520976Smckusick */ 66620976Smckusick dhumctl(dev, bits, how) 66720976Smckusick dev_t dev; 66820976Smckusick int bits, how; 66920976Smckusick { 67020976Smckusick register struct dhudevice *dhuaddr; 67126291Skarels register int unit, mbits; 67220976Smckusick int s; 67320976Smckusick 67420976Smckusick unit = UNIT(dev); 67520976Smckusick dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 67620976Smckusick unit &= 0xf; 67720976Smckusick s = spl5(); 67820976Smckusick dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 67920976Smckusick /* 68020976Smckusick * combine byte from stat register (read only, bits 16..23) 68120976Smckusick * with lcr register (read write, bits 0..15). 68220976Smckusick */ 68320976Smckusick mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 68420976Smckusick switch (how) { 68520976Smckusick case DMSET: 68620976Smckusick mbits = (mbits & 0xff0000) | bits; 68720976Smckusick break; 68820976Smckusick 68920976Smckusick case DMBIS: 69020976Smckusick mbits |= bits; 69120976Smckusick break; 69220976Smckusick 69320976Smckusick case DMBIC: 69420976Smckusick mbits &= ~bits; 69520976Smckusick break; 69620976Smckusick 69720976Smckusick case DMGET: 69820976Smckusick (void) splx(s); 69920976Smckusick return(mbits); 70020976Smckusick } 70120976Smckusick dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 70220976Smckusick dhuaddr->dhulcr2 = DHU_LC2_TXEN; 70320976Smckusick (void) splx(s); 70420976Smckusick return(mbits); 70520976Smckusick } 70620976Smckusick 70720976Smckusick /* 70820976Smckusick * Reset state of driver if UBA reset was necessary. 70920976Smckusick * Reset the line and modem control registers. 71020976Smckusick * restart transmitters. 71120976Smckusick */ 71220976Smckusick dhureset(uban) 71320976Smckusick int uban; 71420976Smckusick { 71520976Smckusick register int dhu, unit; 71620976Smckusick register struct tty *tp; 71720976Smckusick register struct uba_device *ui; 71820976Smckusick register struct dhudevice *addr; 71920976Smckusick int i; 72020976Smckusick 72120976Smckusick for (dhu = 0; dhu < NDHU; dhu++) { 72220976Smckusick ui = dhuinfo[dhu]; 72320976Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 72420976Smckusick continue; 72520976Smckusick printf(" dhu%d", dhu); 72630322Skarels if (dhu_uballoc[uban] == dhu) { 72730322Skarels int info; 72830322Skarels 72930322Skarels info = uballoc(uban, (caddr_t)cfree, 73030322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 73130322Skarels if (info) 73230322Skarels cbase[uban] = UBAI_ADDR(info); 73330322Skarels else { 73430322Skarels printf(" [can't get uba map]"); 73530322Skarels cbase[uban] = -1; 73630322Skarels } 73725434Skarels } 73820976Smckusick addr = (struct dhudevice *)ui->ui_addr; 73920976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 74020976Smckusick addr->dhutimo = DHU_DEF_TIMO; 74120976Smckusick unit = dhu * 16; 74220976Smckusick for (i = 0; i < 16; i++) { 74320976Smckusick tp = &dhu_tty[unit]; 74420976Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 74520976Smckusick dhuparam(unit); 74620976Smckusick (void)dhumctl(unit, DHU_ON, DMSET); 74720976Smckusick tp->t_state &= ~TS_BUSY; 74820976Smckusick dhustart(tp); 74920976Smckusick } 75020976Smckusick unit++; 75120976Smckusick } 75220976Smckusick } 75320976Smckusick } 75420976Smckusick #endif 755