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