123322Smckusick /* 226220Skarels * Copyright (c) 1985 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*26291Skarels * @(#)dhu.c 4.9 (Berkeley) 02/20/86 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 /* 10620976Smckusick * The clist space is mapped by the driver onto each UNIBUS. 10720976Smckusick * The UBACVT macro converts a clist space address for unibus uban 10820976Smckusick * into an i/o space address for the DMA routine. 10920976Smckusick */ 11020976Smckusick int dhu_ubinfo[NUBA]; /* info about allocated unibus map */ 11125434Skarels int cbase[NUBA]; /* base address in unibus map */ 11220976Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 11320976Smckusick 11420976Smckusick /* 11520976Smckusick * Routine for configuration to force a dhu to interrupt. 11620976Smckusick */ 11720976Smckusick /*ARGSUSED*/ 11820976Smckusick dhuprobe(reg) 11920976Smckusick caddr_t reg; 12020976Smckusick { 12120976Smckusick register int br, cvec; /* these are ``value-result'' */ 12220976Smckusick register struct dhudevice *dhuaddr = (struct dhudevice *)reg; 12320976Smckusick int i; 12420976Smckusick 12520976Smckusick #ifdef lint 12620976Smckusick br = 0; cvec = br; br = cvec; 12720976Smckusick if (ndhu == 0) ndhu = 1; 12820976Smckusick dhurint(0); dhuxint(0); 12920976Smckusick #endif 13020976Smckusick /* 13120976Smckusick * The basic idea here is: 13220976Smckusick * do a self-test by setting the Master-Reset bit 13320976Smckusick * if this fails, then return 13420976Smckusick * if successful, there will be 8 diagnostic codes in RX FIFO 13520976Smckusick * therefore ask for a Received-Data-Available interrupt 13620976Smckusick * wait for it... 13720976Smckusick * reset the interrupt-enable bit and flush out the diag. codes 13820976Smckusick */ 13920976Smckusick dhuaddr->dhucsr = DHU_CS_MCLR; 14020976Smckusick for (i = 0; i < 1000; i++) { 14120976Smckusick DELAY(10000); 14220976Smckusick if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0) 14320976Smckusick break; 14420976Smckusick } 14520976Smckusick if (dhuaddr->dhucsr&DHU_CS_MCLR) 14620976Smckusick return(0); 14720976Smckusick if (dhuaddr->dhucsr&DHU_CS_DFAIL) 14820976Smckusick return(0); 14920976Smckusick dhuaddr->dhucsr = DHU_CS_RIE; 15020976Smckusick DELAY(1000); 15120976Smckusick dhuaddr->dhucsr = 0; 15220976Smckusick while (dhuaddr->dhurbuf < 0) 15320976Smckusick /* void */; 15420976Smckusick return (sizeof(struct dhudevice)); 15520976Smckusick } 15620976Smckusick 15720976Smckusick /* 15820976Smckusick * Routine called to attach a dhu. 15920976Smckusick */ 16020976Smckusick dhuattach(ui) 16120976Smckusick struct uba_device *ui; 16220976Smckusick { 16320976Smckusick 16420976Smckusick dhusoftCAR[ui->ui_unit] = ui->ui_flags; 16526220Skarels cbase[ui->ui_ubanum] = -1; 16620976Smckusick } 16720976Smckusick 16820976Smckusick /* 16920976Smckusick * Open a DHU11 line, mapping the clist onto the uba if this 17020976Smckusick * is the first dhu on this uba. Turn on this dhu if this is 17120976Smckusick * the first use of it. 17220976Smckusick */ 17320976Smckusick /*ARGSUSED*/ 17420976Smckusick dhuopen(dev, flag) 17520976Smckusick dev_t dev; 17620976Smckusick { 17720976Smckusick register struct tty *tp; 17820976Smckusick register int unit, dhu; 17920976Smckusick register struct dhudevice *addr; 18020976Smckusick register struct uba_device *ui; 18120976Smckusick int s; 18220976Smckusick 18320976Smckusick unit = UNIT(dev); 18420976Smckusick dhu = unit >> 4; 18520976Smckusick if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0) 18620976Smckusick return (ENXIO); 18720976Smckusick tp = &dhu_tty[unit]; 18820976Smckusick if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 18920976Smckusick return (EBUSY); 19020976Smckusick addr = (struct dhudevice *)ui->ui_addr; 19120976Smckusick tp->t_addr = (caddr_t)addr; 19220976Smckusick tp->t_oproc = dhustart; 19320976Smckusick /* 19420976Smckusick * While setting up state for this uba and this dhu, 19520976Smckusick * block uba resets which can clear the state. 19620976Smckusick */ 19720976Smckusick s = spl5(); 19826220Skarels if (cbase[ui->ui_ubanum] == -1) { 19920976Smckusick dhu_ubinfo[ui->ui_ubanum] = 20020976Smckusick uballoc(ui->ui_ubanum, (caddr_t)cfree, 20120976Smckusick nclist*sizeof(struct cblock), 0); 20226220Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(dhu_ubinfo[ui->ui_ubanum]); 20320976Smckusick } 20420976Smckusick if ((dhuact&(1<<dhu)) == 0) { 20520976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 20620976Smckusick addr->dhutimo = DHU_DEF_TIMO; 20720976Smckusick dhuact |= (1<<dhu); 20820976Smckusick /* anything else to configure whole board */ 20920976Smckusick } 21020976Smckusick (void) splx(s); 21120976Smckusick /* 21220976Smckusick * If this is first open, initialize tty state to default. 21320976Smckusick */ 21420976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 21520976Smckusick ttychars(tp); 21620976Smckusick #ifndef PORTSELECTOR 21720976Smckusick if (tp->t_ispeed == 0) { 21820976Smckusick #else 21920976Smckusick tp->t_state |= TS_HUPCLS; 22020976Smckusick #endif PORTSELECTOR 22120976Smckusick tp->t_ispeed = ISPEED; 22220976Smckusick tp->t_ospeed = ISPEED; 22320976Smckusick tp->t_flags = IFLAGS; 22420976Smckusick #ifndef PORTSELECTOR 22520976Smckusick } 22620976Smckusick #endif PORTSELECTOR 22720976Smckusick tp->t_dev = dev; 22820976Smckusick dhuparam(unit); 22920976Smckusick } 23020976Smckusick /* 23120976Smckusick * Wait for carrier, then process line discipline specific open. 23220976Smckusick */ 23320976Smckusick s = spl5(); 23420976Smckusick if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 23520976Smckusick (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 23620976Smckusick tp->t_state |= TS_CARR_ON; 23720976Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 23820976Smckusick tp->t_state |= TS_WOPEN; 23920976Smckusick sleep((caddr_t)&tp->t_rawq, TTIPRI); 24020976Smckusick } 24120976Smckusick (void) splx(s); 24220976Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp)); 24320976Smckusick } 24420976Smckusick 24520976Smckusick /* 24620976Smckusick * Close a DHU11 line, turning off the modem control. 24720976Smckusick */ 24820976Smckusick /*ARGSUSED*/ 24920976Smckusick dhuclose(dev, flag) 25020976Smckusick dev_t dev; 25120976Smckusick int flag; 25220976Smckusick { 25320976Smckusick register struct tty *tp; 25420976Smckusick register unit; 25520976Smckusick 25620976Smckusick unit = UNIT(dev); 25720976Smckusick tp = &dhu_tty[unit]; 25820976Smckusick (*linesw[tp->t_line].l_close)(tp); 25920976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 26020976Smckusick if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0) 26120976Smckusick #ifdef PORTSELECTOR 26220976Smckusick { 26320976Smckusick extern int wakeup(); 26420976Smckusick 26520976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 26620976Smckusick /* Hold DTR low for 0.5 seconds */ 26720976Smckusick timeout(wakeup, (caddr_t) &tp->t_dev, hz/2); 26820976Smckusick sleep((caddr_t) &tp->t_dev, PZERO); 26920976Smckusick } 27020976Smckusick #else 27120976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 27220976Smckusick #endif PORTSELECTOR 27320976Smckusick ttyclose(tp); 27420976Smckusick } 27520976Smckusick 27620976Smckusick dhuread(dev, uio) 27720976Smckusick dev_t dev; 27820976Smckusick struct uio *uio; 27920976Smckusick { 28020976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 28120976Smckusick 28220976Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio)); 28320976Smckusick } 28420976Smckusick 28520976Smckusick dhuwrite(dev, uio) 28620976Smckusick dev_t dev; 28720976Smckusick struct uio *uio; 28820976Smckusick { 28920976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 29020976Smckusick 29120976Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio)); 29220976Smckusick } 29320976Smckusick 29420976Smckusick /* 29520976Smckusick * DHU11 receiver interrupt. 29620976Smckusick */ 29720976Smckusick dhurint(dhu) 29820976Smckusick int dhu; 29920976Smckusick { 30020976Smckusick register struct tty *tp; 30120976Smckusick register c; 30220976Smckusick register struct dhudevice *addr; 30320976Smckusick register struct tty *tp0; 30420976Smckusick register struct uba_device *ui; 30520976Smckusick register line; 30620976Smckusick int overrun = 0; 30720976Smckusick 30820976Smckusick ui = dhuinfo[dhu]; 30920976Smckusick if (ui == 0 || ui->ui_alive == 0) 31020976Smckusick return; 31120976Smckusick addr = (struct dhudevice *)ui->ui_addr; 31220976Smckusick tp0 = &dhu_tty[dhu<<4]; 31320976Smckusick /* 31420976Smckusick * Loop fetching characters from the silo for this 31520976Smckusick * dhu until there are no more in the silo. 31620976Smckusick */ 31720976Smckusick while ((c = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 31820976Smckusick line = DHU_RX_LINE(c); 31920976Smckusick tp = tp0 + line; 32020976Smckusick if ((c & DHU_RB_STAT) == DHU_RB_STAT) { 32120976Smckusick /* 32220976Smckusick * modem changed or diag info 32320976Smckusick */ 32420976Smckusick if (c & DHU_RB_DIAG) { 32520976Smckusick /* decode diagnostic messages */ 32620976Smckusick continue; 32720976Smckusick } 32825395Skarels if (c & DHU_ST_DCD) 32925395Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 33025395Skarels else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 33125395Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 33225395Skarels (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 33320976Smckusick continue; 33420976Smckusick } 33520976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 33620976Smckusick wakeup((caddr_t)&tp->t_rawq); 33720976Smckusick #ifdef PORTSELECTOR 33820976Smckusick if ((tp->t_state&TS_WOPEN) == 0) 33920976Smckusick #endif 34025395Skarels continue; 34120976Smckusick } 34220976Smckusick if (c & DHU_RB_PE) 34320976Smckusick if ((tp->t_flags&(EVENP|ODDP)) == EVENP || 34420976Smckusick (tp->t_flags&(EVENP|ODDP)) == ODDP) 34520976Smckusick continue; 34620976Smckusick if ((c & DHU_RB_DO) && overrun == 0) { 34724841Seric log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 34820976Smckusick overrun = 1; 34920976Smckusick } 35020976Smckusick if (c & DHU_RB_FE) 35120976Smckusick /* 35220976Smckusick * At framing error (break) generate 35320976Smckusick * a null (in raw mode, for getty), or a 35420976Smckusick * interrupt (in cooked/cbreak mode). 35520976Smckusick */ 35620976Smckusick if (tp->t_flags&RAW) 35720976Smckusick c = 0; 35820976Smckusick else 35920976Smckusick c = tp->t_intrc; 36020976Smckusick #if NBK > 0 36120976Smckusick if (tp->t_line == NETLDISC) { 36220976Smckusick c &= 0x7f; 36320976Smckusick BKINPUT(c, tp); 36420976Smckusick } else 36520976Smckusick #endif 36620976Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 36720976Smckusick } 36820976Smckusick } 36920976Smckusick 37020976Smckusick /* 37120976Smckusick * Ioctl for DHU11. 37220976Smckusick */ 37320976Smckusick /*ARGSUSED*/ 37420976Smckusick dhuioctl(dev, cmd, data, flag) 37520976Smckusick caddr_t data; 37620976Smckusick { 37720976Smckusick register struct tty *tp; 37820976Smckusick register int unit = UNIT(dev); 37920976Smckusick int error; 38020976Smckusick 38120976Smckusick tp = &dhu_tty[unit]; 38220976Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 38320976Smckusick if (error >= 0) 38420976Smckusick return (error); 38520976Smckusick error = ttioctl(tp, cmd, data, flag); 38620976Smckusick if (error >= 0) { 38720976Smckusick if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET || 38820976Smckusick cmd == TIOCLBIC || cmd == TIOCLBIS) 38920976Smckusick dhuparam(unit); 39020976Smckusick return (error); 39120976Smckusick } 39220976Smckusick 39320976Smckusick switch (cmd) { 39420976Smckusick case TIOCSBRK: 39520976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIS); 39620976Smckusick break; 39720976Smckusick 39820976Smckusick case TIOCCBRK: 39920976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 40020976Smckusick break; 40120976Smckusick 40220976Smckusick case TIOCSDTR: 40320976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 40420976Smckusick break; 40520976Smckusick 40620976Smckusick case TIOCCDTR: 40720976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 40820976Smckusick break; 40920976Smckusick 41020976Smckusick case TIOCMSET: 41120976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 41220976Smckusick break; 41320976Smckusick 41420976Smckusick case TIOCMBIS: 41520976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 41620976Smckusick break; 41720976Smckusick 41820976Smckusick case TIOCMBIC: 41920976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 42020976Smckusick break; 42120976Smckusick 42220976Smckusick case TIOCMGET: 42320976Smckusick *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 42420976Smckusick break; 42520976Smckusick default: 42620976Smckusick return (ENOTTY); 42720976Smckusick } 42820976Smckusick return (0); 42920976Smckusick } 43020976Smckusick 43120976Smckusick dmtodhu(bits) 43220976Smckusick register int bits; 43320976Smckusick { 43420976Smckusick register int b = 0; 43520976Smckusick 43620976Smckusick if (bits & DML_RTS) b |= DHU_RTS; 43720976Smckusick if (bits & DML_DTR) b |= DHU_DTR; 43820976Smckusick if (bits & DML_LE) b |= DHU_LE; 43920976Smckusick return(b); 44020976Smckusick } 44120976Smckusick 44220976Smckusick dhutodm(bits) 44320976Smckusick register int bits; 44420976Smckusick { 44520976Smckusick register int b = 0; 44620976Smckusick 44720976Smckusick if (bits & DHU_DSR) b |= DML_DSR; 44820976Smckusick if (bits & DHU_RNG) b |= DML_RNG; 44920976Smckusick if (bits & DHU_CAR) b |= DML_CAR; 45020976Smckusick if (bits & DHU_CTS) b |= DML_CTS; 45120976Smckusick if (bits & DHU_RTS) b |= DML_RTS; 45220976Smckusick if (bits & DHU_DTR) b |= DML_DTR; 45320976Smckusick if (bits & DHU_LE) b |= DML_LE; 45420976Smckusick return(b); 45520976Smckusick } 45620976Smckusick 45720976Smckusick 45820976Smckusick /* 45920976Smckusick * Set parameters from open or stty into the DHU hardware 46020976Smckusick * registers. 46120976Smckusick */ 46220976Smckusick dhuparam(unit) 46320976Smckusick register int unit; 46420976Smckusick { 46520976Smckusick register struct tty *tp; 46620976Smckusick register struct dhudevice *addr; 46720976Smckusick register int lpar; 46820976Smckusick int s; 46920976Smckusick 47020976Smckusick tp = &dhu_tty[unit]; 47120976Smckusick addr = (struct dhudevice *)tp->t_addr; 47220976Smckusick /* 47320976Smckusick * Block interrupts so parameters will be set 47420976Smckusick * before the line interrupts. 47520976Smckusick */ 47620976Smckusick s = spl5(); 47720976Smckusick if ((tp->t_ispeed) == 0) { 47820976Smckusick tp->t_state |= TS_HUPCLS; 47920976Smckusick (void)dhumctl(unit, DHU_OFF, DMSET); 48020976Smckusick splx(s); 48120976Smckusick return; 48220976Smckusick } 48320976Smckusick lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8); 48420976Smckusick if ((tp->t_ispeed) == B134) 48520976Smckusick lpar |= DHU_LP_BITS6|DHU_LP_PENABLE; 48624270Slepreau else if (tp->t_flags & (RAW|LITOUT|PASS8)) 48720976Smckusick lpar |= DHU_LP_BITS8; 48820976Smckusick else 48920976Smckusick lpar |= DHU_LP_BITS7|DHU_LP_PENABLE; 49020976Smckusick if (tp->t_flags&EVENP) 49120976Smckusick lpar |= DHU_LP_EPAR; 49220976Smckusick if ((tp->t_ospeed) == B110) 49320976Smckusick lpar |= DHU_LP_TWOSB; 49420976Smckusick addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 49520976Smckusick addr->dhulpr = lpar; 49620976Smckusick splx(s); 49720976Smckusick } 49820976Smckusick 49920976Smckusick /* 50020976Smckusick * DHU11 transmitter interrupt. 50120976Smckusick * Restart each line which used to be active but has 50220976Smckusick * terminated transmission since the last interrupt. 50320976Smckusick */ 50420976Smckusick dhuxint(dhu) 50520976Smckusick int dhu; 50620976Smckusick { 50720976Smckusick register struct tty *tp; 50820976Smckusick register struct dhudevice *addr; 50920976Smckusick register struct tty *tp0; 51020976Smckusick register struct uba_device *ui; 51120976Smckusick register int line, t; 51220976Smckusick u_short cntr; 51320976Smckusick 51420976Smckusick ui = dhuinfo[dhu]; 51520976Smckusick tp0 = &dhu_tty[dhu<<4]; 51620976Smckusick addr = (struct dhudevice *)ui->ui_addr; 51720976Smckusick while ((t = addr->dhucsrh) & DHU_CSH_TI) { 51820976Smckusick line = DHU_TX_LINE(t); 51920976Smckusick tp = tp0 + line; 52020976Smckusick tp->t_state &= ~TS_BUSY; 52120976Smckusick if (t & DHU_CSH_NXM) { 52220976Smckusick printf("dhu(%d,%d): NXM fault\n", dhu, line); 52320976Smckusick /* SHOULD RESTART OR SOMETHING... */ 52420976Smckusick } 52520976Smckusick if (tp->t_state&TS_FLUSH) 52620976Smckusick tp->t_state &= ~TS_FLUSH; 52720976Smckusick else { 52820976Smckusick addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 52920976Smckusick /* 53020976Smckusick * Do arithmetic in a short to make up 53120976Smckusick * for lost 16&17 bits. 53220976Smckusick */ 53320976Smckusick cntr = addr->dhubar1 - 53420976Smckusick UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 53520976Smckusick ndflush(&tp->t_outq, (int)cntr); 53620976Smckusick } 53720976Smckusick if (tp->t_line) 53820976Smckusick (*linesw[tp->t_line].l_start)(tp); 53920976Smckusick else 54020976Smckusick dhustart(tp); 54120976Smckusick } 54220976Smckusick } 54320976Smckusick 54420976Smckusick /* 54520976Smckusick * Start (restart) transmission on the given DHU11 line. 54620976Smckusick */ 54720976Smckusick dhustart(tp) 54820976Smckusick register struct tty *tp; 54920976Smckusick { 55020976Smckusick register struct dhudevice *addr; 55120976Smckusick register int car, dhu, unit, nch; 55220976Smckusick int s; 55320976Smckusick 55420976Smckusick unit = minor(tp->t_dev); 55520976Smckusick dhu = unit >> 4; 55620976Smckusick unit &= 0xf; 55720976Smckusick addr = (struct dhudevice *)tp->t_addr; 55820976Smckusick 55920976Smckusick /* 56020976Smckusick * Must hold interrupts in following code to prevent 56120976Smckusick * state of the tp from changing. 56220976Smckusick */ 56320976Smckusick s = spl5(); 56420976Smckusick /* 56520976Smckusick * If it's currently active, or delaying, no need to do anything. 56620976Smckusick */ 56720976Smckusick if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 56820976Smckusick goto out; 56920976Smckusick /* 57020976Smckusick * If there are sleepers, and output has drained below low 57120976Smckusick * water mark, wake up the sleepers.. 57220976Smckusick */ 57320976Smckusick if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 57420976Smckusick if (tp->t_state&TS_ASLEEP) { 57520976Smckusick tp->t_state &= ~TS_ASLEEP; 57620976Smckusick wakeup((caddr_t)&tp->t_outq); 57720976Smckusick } 57820976Smckusick if (tp->t_wsel) { 57920976Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 58020976Smckusick tp->t_wsel = 0; 58120976Smckusick tp->t_state &= ~TS_WCOLL; 58220976Smckusick } 58320976Smckusick } 58420976Smckusick /* 58520976Smckusick * Now restart transmission unless the output queue is 58620976Smckusick * empty. 58720976Smckusick */ 58820976Smckusick if (tp->t_outq.c_cc == 0) 58920976Smckusick goto out; 59020976Smckusick if (tp->t_flags & (RAW|LITOUT)) 59120976Smckusick nch = ndqb(&tp->t_outq, 0); 59220976Smckusick else { 59320976Smckusick nch = ndqb(&tp->t_outq, 0200); 59420976Smckusick /* 59520976Smckusick * If first thing on queue is a delay process it. 59620976Smckusick */ 59720976Smckusick if (nch == 0) { 59820976Smckusick nch = getc(&tp->t_outq); 59920976Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 60020976Smckusick tp->t_state |= TS_TIMEOUT; 60120976Smckusick goto out; 60220976Smckusick } 60320976Smckusick } 60420976Smckusick /* 60520976Smckusick * If characters to transmit, restart transmission. 60620976Smckusick */ 60720976Smckusick if (nch) { 60820976Smckusick car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 60920976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 61020976Smckusick addr->dhulcr &= ~DHU_LC_TXABORT; 61120976Smckusick addr->dhubcr = nch; 61220976Smckusick addr->dhubar1 = car; 61320976Smckusick addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 61420976Smckusick DHU_BA2_DMAGO; 61520976Smckusick tp->t_state |= TS_BUSY; 61620976Smckusick } 61720976Smckusick out: 61820976Smckusick splx(s); 61920976Smckusick } 62020976Smckusick 62120976Smckusick /* 62220976Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush. 62320976Smckusick */ 62420976Smckusick /*ARGSUSED*/ 62520976Smckusick dhustop(tp, flag) 62620976Smckusick register struct tty *tp; 62720976Smckusick { 62820976Smckusick register struct dhudevice *addr; 62920976Smckusick register int unit, s; 63020976Smckusick 63120976Smckusick addr = (struct dhudevice *)tp->t_addr; 63220976Smckusick /* 63320976Smckusick * Block input/output interrupts while messing with state. 63420976Smckusick */ 63520976Smckusick s = spl5(); 63620976Smckusick if (tp->t_state & TS_BUSY) { 63720976Smckusick /* 63820976Smckusick * Device is transmitting; stop output 63920976Smckusick * by selecting the line and setting the 64020976Smckusick * abort xmit bit. We will get an xmit interrupt, 64120976Smckusick * where we will figure out where to continue the 64220976Smckusick * next time the transmitter is enabled. If 64320976Smckusick * TS_FLUSH is set, the outq will be flushed. 64420976Smckusick * In either case, dhustart will clear the TXABORT bit. 64520976Smckusick */ 64620976Smckusick unit = minor(tp->t_dev); 64720976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 64820976Smckusick addr->dhulcr |= DHU_LC_TXABORT; 64920976Smckusick if ((tp->t_state&TS_TTSTOP)==0) 65020976Smckusick tp->t_state |= TS_FLUSH; 65120976Smckusick } 65220976Smckusick (void) splx(s); 65320976Smckusick } 65420976Smckusick 65520976Smckusick /* 65620976Smckusick * DHU11 modem control 65720976Smckusick */ 65820976Smckusick dhumctl(dev, bits, how) 65920976Smckusick dev_t dev; 66020976Smckusick int bits, how; 66120976Smckusick { 66220976Smckusick register struct dhudevice *dhuaddr; 663*26291Skarels register int unit, mbits; 66420976Smckusick int s; 66520976Smckusick 66620976Smckusick unit = UNIT(dev); 66720976Smckusick dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 66820976Smckusick unit &= 0xf; 66920976Smckusick s = spl5(); 67020976Smckusick dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 67120976Smckusick /* 67220976Smckusick * combine byte from stat register (read only, bits 16..23) 67320976Smckusick * with lcr register (read write, bits 0..15). 67420976Smckusick */ 67520976Smckusick mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 67620976Smckusick switch (how) { 67720976Smckusick case DMSET: 67820976Smckusick mbits = (mbits & 0xff0000) | bits; 67920976Smckusick break; 68020976Smckusick 68120976Smckusick case DMBIS: 68220976Smckusick mbits |= bits; 68320976Smckusick break; 68420976Smckusick 68520976Smckusick case DMBIC: 68620976Smckusick mbits &= ~bits; 68720976Smckusick break; 68820976Smckusick 68920976Smckusick case DMGET: 69020976Smckusick (void) splx(s); 69120976Smckusick return(mbits); 69220976Smckusick } 69320976Smckusick dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 69420976Smckusick dhuaddr->dhulcr2 = DHU_LC2_TXEN; 69520976Smckusick (void) splx(s); 69620976Smckusick return(mbits); 69720976Smckusick } 69820976Smckusick 69920976Smckusick /* 70020976Smckusick * Reset state of driver if UBA reset was necessary. 70120976Smckusick * Reset the line and modem control registers. 70220976Smckusick * restart transmitters. 70320976Smckusick */ 70420976Smckusick dhureset(uban) 70520976Smckusick int uban; 70620976Smckusick { 70720976Smckusick register int dhu, unit; 70820976Smckusick register struct tty *tp; 70920976Smckusick register struct uba_device *ui; 71020976Smckusick register struct dhudevice *addr; 71120976Smckusick int i; 71220976Smckusick 71320976Smckusick for (dhu = 0; dhu < NDHU; dhu++) { 71420976Smckusick ui = dhuinfo[dhu]; 71520976Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 71620976Smckusick continue; 71720976Smckusick printf(" dhu%d", dhu); 71826220Skarels if (dhu_ubinfo[uban]) { 71925434Skarels dhu_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 72025434Skarels nclist*sizeof (struct cblock), 0); 72126220Skarels cbase[uban] = UBAI_ADDR(dhu_ubinfo[uban]); 72225434Skarels } 72320976Smckusick addr = (struct dhudevice *)ui->ui_addr; 72420976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 72520976Smckusick addr->dhutimo = DHU_DEF_TIMO; 72620976Smckusick unit = dhu * 16; 72720976Smckusick for (i = 0; i < 16; i++) { 72820976Smckusick tp = &dhu_tty[unit]; 72920976Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 73020976Smckusick dhuparam(unit); 73120976Smckusick (void)dhumctl(unit, DHU_ON, DMSET); 73220976Smckusick tp->t_state &= ~TS_BUSY; 73320976Smckusick dhustart(tp); 73420976Smckusick } 73520976Smckusick unit++; 73620976Smckusick } 73720976Smckusick } 73820976Smckusick } 73920976Smckusick #endif 740