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*39061Smarc * @(#)dhu.c 7.7 (Berkeley) 09/06/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 */ 2237514Smckusick #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" 3237606Smarc #include "ttydefaults.h" 3320976Smckusick #include "map.h" 3420976Smckusick #include "buf.h" 3520976Smckusick #include "vm.h" 3620976Smckusick #include "kernel.h" 3720976Smckusick #include "syslog.h" 3820976Smckusick 3920976Smckusick #include "uba.h" 4020976Smckusick #include "ubareg.h" 4120976Smckusick #include "ubavar.h" 4220976Smckusick #include "dhureg.h" 4320976Smckusick 4420976Smckusick #include "bkmac.h" 4520976Smckusick #include "clist.h" 4620976Smckusick #include "file.h" 4720976Smckusick #include "uio.h" 4820976Smckusick 4920976Smckusick /* 5020976Smckusick * Definition of the driver for the auto-configuration program. 5120976Smckusick */ 5220976Smckusick int dhuprobe(), dhuattach(), dhurint(), dhuxint(); 5320976Smckusick struct uba_device *dhuinfo[NDHU]; 5425519Stef u_short dhustd[] = { 160440, 160500, 0 }; /* some common addresses */ 5520976Smckusick struct uba_driver dhudriver = 5620976Smckusick { dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo }; 5720976Smckusick 5820976Smckusick #define NDHULINE (NDHU*16) 5920976Smckusick 6020976Smckusick #define UNIT(x) (minor(x)) 6120976Smckusick 6220976Smckusick #ifndef PORTSELECTOR 6337606Smarc #define SPEED TTYDEF_SPEED 6437606Smarc #define LFLAG TTYDEF_LFLAG 6520976Smckusick #else 6637606Smarc #define SPEED B4800 6737606Smarc #define LFLAG (TTYDEF_LFLAG & ~ECHO) 6820976Smckusick #endif 6920976Smckusick 7020976Smckusick /* 7120976Smckusick * default receive silo timeout value -- valid values are 2..255 7220976Smckusick * number of ms. to delay between first char received and receive interrupt 7320976Smckusick * 7420976Smckusick * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0 7520976Smckusick */ 7620976Smckusick #define DHU_DEF_TIMO 20 7720976Smckusick 7820976Smckusick /* 7920976Smckusick * Other values for silo timeout register defined here but not used: 8020976Smckusick * receive interrupt only on modem control or silo alarm (3/4 full) 8120976Smckusick */ 8220976Smckusick #define DHU_POLL_TIMO 0 8320976Smckusick /* 8420976Smckusick * receive interrupt immediately on receive character 8520976Smckusick */ 8620976Smckusick #define DHU_NO_TIMO 1 8720976Smckusick 8820976Smckusick /* 8920976Smckusick * Local variables for the driver 9020976Smckusick */ 9120976Smckusick /* 9220976Smckusick * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B". 9320976Smckusick * EXTA => 19200 baud 9420976Smckusick * EXTB => 2000 baud 9520976Smckusick */ 9637606Smarc struct speedtab dhuspeedtab[] = { 9737606Smarc 19200, 14, 9837606Smarc 9600, 13, 9937606Smarc 4800, 11, 10037606Smarc 2400, 10, 10137606Smarc 2000, 9, 10237606Smarc 1800, 8, 10337606Smarc 1200, 7, 10437606Smarc 600, 6, 10537606Smarc 300, 5, 10637606Smarc 150, 4, 10737606Smarc 134, 3, 10837606Smarc 110, 2, 10937606Smarc 75, 1, 11037606Smarc 0, 0, 111*39061Smarc EXTA, 14, 112*39061Smarc EXTB, 9, 11337606Smarc -1, -1, 11437606Smarc }; 11520976Smckusick 11620976Smckusick short dhusoftCAR[NDHU]; 11720976Smckusick 11820976Smckusick struct tty dhu_tty[NDHULINE]; 11920976Smckusick int ndhu = NDHULINE; 12020976Smckusick int dhuact; /* mask of active dhu's */ 12120976Smckusick int dhustart(), ttrstrt(); 12220976Smckusick 12320976Smckusick /* 12430322Skarels * The clist space is mapped by one terminal driver onto each UNIBUS. 12530322Skarels * The identity of the board which allocated resources is recorded, 12630322Skarels * so the process may be repeated after UNIBUS resets. 12720976Smckusick * The UBACVT macro converts a clist space address for unibus uban 12820976Smckusick * into an i/o space address for the DMA routine. 12920976Smckusick */ 13030322Skarels int dhu_uballoc[NUBA]; /* which dhu (if any) allocated unibus map */ 13130322Skarels int cbase[NUBA]; /* base address of clists in unibus map */ 13220976Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 13320976Smckusick 13420976Smckusick /* 13520976Smckusick * Routine for configuration to force a dhu to interrupt. 13620976Smckusick */ 13720976Smckusick /*ARGSUSED*/ 13820976Smckusick dhuprobe(reg) 13920976Smckusick caddr_t reg; 14020976Smckusick { 14120976Smckusick register int br, cvec; /* these are ``value-result'' */ 14220976Smckusick register struct dhudevice *dhuaddr = (struct dhudevice *)reg; 14320976Smckusick int i; 14420976Smckusick 14520976Smckusick #ifdef lint 14620976Smckusick br = 0; cvec = br; br = cvec; 14720976Smckusick if (ndhu == 0) ndhu = 1; 14820976Smckusick dhurint(0); dhuxint(0); 14920976Smckusick #endif 15020976Smckusick /* 15120976Smckusick * The basic idea here is: 15220976Smckusick * do a self-test by setting the Master-Reset bit 15320976Smckusick * if this fails, then return 15420976Smckusick * if successful, there will be 8 diagnostic codes in RX FIFO 15520976Smckusick * therefore ask for a Received-Data-Available interrupt 15620976Smckusick * wait for it... 15720976Smckusick * reset the interrupt-enable bit and flush out the diag. codes 15820976Smckusick */ 15920976Smckusick dhuaddr->dhucsr = DHU_CS_MCLR; 16020976Smckusick for (i = 0; i < 1000; i++) { 16120976Smckusick DELAY(10000); 16220976Smckusick if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0) 16320976Smckusick break; 16420976Smckusick } 16520976Smckusick if (dhuaddr->dhucsr&DHU_CS_MCLR) 16620976Smckusick return(0); 16720976Smckusick if (dhuaddr->dhucsr&DHU_CS_DFAIL) 16820976Smckusick return(0); 16920976Smckusick dhuaddr->dhucsr = DHU_CS_RIE; 17020976Smckusick DELAY(1000); 17120976Smckusick dhuaddr->dhucsr = 0; 17220976Smckusick while (dhuaddr->dhurbuf < 0) 17320976Smckusick /* void */; 17420976Smckusick return (sizeof(struct dhudevice)); 17520976Smckusick } 17620976Smckusick 17720976Smckusick /* 17820976Smckusick * Routine called to attach a dhu. 17920976Smckusick */ 18020976Smckusick dhuattach(ui) 18120976Smckusick struct uba_device *ui; 18220976Smckusick { 18320976Smckusick 18420976Smckusick dhusoftCAR[ui->ui_unit] = ui->ui_flags; 18526220Skarels cbase[ui->ui_ubanum] = -1; 18636610Sbostic dhu_uballoc[ui->ui_ubanum] = -1; 18720976Smckusick } 18820976Smckusick 18920976Smckusick /* 19020976Smckusick * Open a DHU11 line, mapping the clist onto the uba if this 19120976Smckusick * is the first dhu on this uba. Turn on this dhu if this is 19220976Smckusick * the first use of it. 19320976Smckusick */ 19420976Smckusick /*ARGSUSED*/ 19520976Smckusick dhuopen(dev, flag) 19620976Smckusick dev_t dev; 19720976Smckusick { 19820976Smckusick register struct tty *tp; 19920976Smckusick register int unit, dhu; 20020976Smckusick register struct dhudevice *addr; 20120976Smckusick register struct uba_device *ui; 20220976Smckusick int s; 20337606Smarc extern dhuparam(); 20420976Smckusick 20520976Smckusick unit = UNIT(dev); 20620976Smckusick dhu = unit >> 4; 20720976Smckusick if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0) 20820976Smckusick return (ENXIO); 20920976Smckusick tp = &dhu_tty[unit]; 21020976Smckusick if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 21120976Smckusick return (EBUSY); 21220976Smckusick addr = (struct dhudevice *)ui->ui_addr; 21320976Smckusick tp->t_addr = (caddr_t)addr; 21420976Smckusick tp->t_oproc = dhustart; 21537606Smarc tp->t_param = dhuparam; 21620976Smckusick /* 21720976Smckusick * While setting up state for this uba and this dhu, 21820976Smckusick * block uba resets which can clear the state. 21920976Smckusick */ 22020976Smckusick s = spl5(); 22126220Skarels if (cbase[ui->ui_ubanum] == -1) { 22230322Skarels dhu_uballoc[ui->ui_ubanum] = dhu; 22330322Skarels cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, 22430322Skarels (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); 22520976Smckusick } 22620976Smckusick if ((dhuact&(1<<dhu)) == 0) { 22720976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 22820976Smckusick addr->dhutimo = DHU_DEF_TIMO; 22920976Smckusick dhuact |= (1<<dhu); 23020976Smckusick /* anything else to configure whole board */ 23120976Smckusick } 23220976Smckusick (void) splx(s); 23320976Smckusick /* 23420976Smckusick * If this is first open, initialize tty state to default. 23520976Smckusick */ 23620976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 23720976Smckusick ttychars(tp); 23820976Smckusick #ifndef PORTSELECTOR 23937606Smarc if (tp->t_ospeed == 0) { 24037606Smarc #endif 24137606Smarc tp->t_ispeed = SPEED; 24237606Smarc tp->t_ospeed = SPEED; 24337606Smarc ttsetwater(tp); 24437606Smarc tp->t_iflag = TTYDEF_IFLAG; 24537606Smarc tp->t_oflag = TTYDEF_OFLAG; 24637606Smarc tp->t_lflag = LFLAG; 24737606Smarc tp->t_cflag = TTYDEF_CFLAG; 24837606Smarc #ifdef PORTSELECTOR 24937606Smarc tp->t_cflag |= HUPCL; 25037606Smarc #else 25120976Smckusick } 25237606Smarc #endif 25320976Smckusick tp->t_dev = dev; 25437606Smarc dhuparam(tp, &tp->t_termios); 25520976Smckusick } 25620976Smckusick /* 25720976Smckusick * Wait for carrier, then process line discipline specific open. 25820976Smckusick */ 25937606Smarc s = spltty(); 26020976Smckusick if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 26120976Smckusick (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 26220976Smckusick tp->t_state |= TS_CARR_ON; 263*39061Smarc while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) && 264*39061Smarc (tp->t_state & TS_CARR_ON) == 0) { 26520976Smckusick tp->t_state |= TS_WOPEN; 26620976Smckusick sleep((caddr_t)&tp->t_rawq, TTIPRI); 26720976Smckusick } 26820976Smckusick (void) splx(s); 26920976Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp)); 27020976Smckusick } 27120976Smckusick 27220976Smckusick /* 27320976Smckusick * Close a DHU11 line, turning off the modem control. 27420976Smckusick */ 27520976Smckusick /*ARGSUSED*/ 27620976Smckusick dhuclose(dev, flag) 27720976Smckusick dev_t dev; 27820976Smckusick int flag; 27920976Smckusick { 28020976Smckusick register struct tty *tp; 28120976Smckusick register unit; 28220976Smckusick 28320976Smckusick unit = UNIT(dev); 28420976Smckusick tp = &dhu_tty[unit]; 28520976Smckusick (*linesw[tp->t_line].l_close)(tp); 28620976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 28737606Smarc if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) || 28837606Smarc (tp->t_state&TS_ISOPEN)==0) 28920976Smckusick #ifdef PORTSELECTOR 29020976Smckusick { 29120976Smckusick extern int wakeup(); 29220976Smckusick 29320976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 29420976Smckusick /* Hold DTR low for 0.5 seconds */ 29520976Smckusick timeout(wakeup, (caddr_t) &tp->t_dev, hz/2); 29620976Smckusick sleep((caddr_t) &tp->t_dev, PZERO); 29720976Smckusick } 29820976Smckusick #else 29920976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 30020976Smckusick #endif PORTSELECTOR 30120976Smckusick ttyclose(tp); 30220976Smckusick } 30320976Smckusick 304*39061Smarc dhuread(dev, uio, flag) 30520976Smckusick dev_t dev; 30620976Smckusick struct uio *uio; 30720976Smckusick { 30820976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 30920976Smckusick 310*39061Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 31120976Smckusick } 31220976Smckusick 313*39061Smarc dhuwrite(dev, uio, flag) 31420976Smckusick dev_t dev; 31520976Smckusick struct uio *uio; 31620976Smckusick { 31720976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 31820976Smckusick 319*39061Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 32020976Smckusick } 32120976Smckusick 32220976Smckusick /* 32320976Smckusick * DHU11 receiver interrupt. 32420976Smckusick */ 32520976Smckusick dhurint(dhu) 32620976Smckusick int dhu; 32720976Smckusick { 32820976Smckusick register struct tty *tp; 32937606Smarc register creg, c; 33020976Smckusick register struct dhudevice *addr; 33120976Smckusick register struct tty *tp0; 33220976Smckusick register struct uba_device *ui; 33320976Smckusick register line; 33420976Smckusick int overrun = 0; 33520976Smckusick 33635401Stef #ifdef QBA 33737606Smarc (void) spltty(); 33827256Skridle #endif 33920976Smckusick ui = dhuinfo[dhu]; 34020976Smckusick if (ui == 0 || ui->ui_alive == 0) 34120976Smckusick return; 34220976Smckusick addr = (struct dhudevice *)ui->ui_addr; 34320976Smckusick tp0 = &dhu_tty[dhu<<4]; 34420976Smckusick /* 34520976Smckusick * Loop fetching characters from the silo for this 34620976Smckusick * dhu until there are no more in the silo. 34720976Smckusick */ 34837606Smarc while ((creg = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 34937606Smarc line = DHU_RX_LINE(creg); 35020976Smckusick tp = tp0 + line; 35137606Smarc c = creg & 0xff; 35237606Smarc if ((creg & DHU_RB_STAT) == DHU_RB_STAT) { 35320976Smckusick /* 35420976Smckusick * modem changed or diag info 35520976Smckusick */ 35637606Smarc if (creg & DHU_RB_DIAG) { 35720976Smckusick /* decode diagnostic messages */ 35820976Smckusick continue; 35920976Smckusick } 36037606Smarc if (creg & DHU_ST_DCD) 36125395Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 36225395Skarels else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 36325395Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 36425395Skarels (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 36520976Smckusick continue; 36620976Smckusick } 36720976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 36820976Smckusick wakeup((caddr_t)&tp->t_rawq); 36920976Smckusick #ifdef PORTSELECTOR 37020976Smckusick if ((tp->t_state&TS_WOPEN) == 0) 37120976Smckusick #endif 37225395Skarels continue; 37320976Smckusick } 374*39061Smarc if (creg & DHU_RB_PE) 375*39061Smarc c |= TTY_PE; 376*39061Smarc if (creg & DHU_RB_DO && overrun == 0) { 377*39061Smarc log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 378*39061Smarc overrun = 1; 37920976Smckusick } 380*39061Smarc if (creg & DHU_RB_FE) 381*39061Smarc c |= TTY_FE; 38237606Smarc 383*39061Smarc (*linesw[tp->t_line].l_rint)(c, tp); 38420976Smckusick } 38520976Smckusick } 38620976Smckusick 38720976Smckusick /* 38820976Smckusick * Ioctl for DHU11. 38920976Smckusick */ 39020976Smckusick /*ARGSUSED*/ 39120976Smckusick dhuioctl(dev, cmd, data, flag) 39220976Smckusick caddr_t data; 39320976Smckusick { 39420976Smckusick register struct tty *tp; 39520976Smckusick register int unit = UNIT(dev); 39620976Smckusick int error; 39720976Smckusick 39820976Smckusick tp = &dhu_tty[unit]; 39920976Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 40020976Smckusick if (error >= 0) 40120976Smckusick return (error); 40220976Smckusick error = ttioctl(tp, cmd, data, flag); 40337606Smarc if (error >= 0) 40420976Smckusick return (error); 40520976Smckusick 40620976Smckusick switch (cmd) { 40720976Smckusick case TIOCSBRK: 40820976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIS); 40920976Smckusick break; 41020976Smckusick 41120976Smckusick case TIOCCBRK: 41220976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 41320976Smckusick break; 41420976Smckusick 41520976Smckusick case TIOCSDTR: 41620976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 41720976Smckusick break; 41820976Smckusick 41920976Smckusick case TIOCCDTR: 42020976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 42120976Smckusick break; 42220976Smckusick 42320976Smckusick case TIOCMSET: 42420976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 42520976Smckusick break; 42620976Smckusick 42720976Smckusick case TIOCMBIS: 42820976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 42920976Smckusick break; 43020976Smckusick 43120976Smckusick case TIOCMBIC: 43220976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 43320976Smckusick break; 43420976Smckusick 43520976Smckusick case TIOCMGET: 43620976Smckusick *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 43720976Smckusick break; 43820976Smckusick default: 43920976Smckusick return (ENOTTY); 44020976Smckusick } 44120976Smckusick return (0); 44220976Smckusick } 44320976Smckusick 44420976Smckusick dmtodhu(bits) 44520976Smckusick register int bits; 44620976Smckusick { 44720976Smckusick register int b = 0; 44820976Smckusick 44920976Smckusick if (bits & DML_RTS) b |= DHU_RTS; 45020976Smckusick if (bits & DML_DTR) b |= DHU_DTR; 45120976Smckusick if (bits & DML_LE) b |= DHU_LE; 45220976Smckusick return(b); 45320976Smckusick } 45420976Smckusick 45520976Smckusick dhutodm(bits) 45620976Smckusick register int bits; 45720976Smckusick { 45820976Smckusick register int b = 0; 45920976Smckusick 46020976Smckusick if (bits & DHU_DSR) b |= DML_DSR; 46120976Smckusick if (bits & DHU_RNG) b |= DML_RNG; 46220976Smckusick if (bits & DHU_CAR) b |= DML_CAR; 46320976Smckusick if (bits & DHU_CTS) b |= DML_CTS; 46420976Smckusick if (bits & DHU_RTS) b |= DML_RTS; 46520976Smckusick if (bits & DHU_DTR) b |= DML_DTR; 46620976Smckusick if (bits & DHU_LE) b |= DML_LE; 46720976Smckusick return(b); 46820976Smckusick } 46920976Smckusick 47020976Smckusick 47120976Smckusick /* 47220976Smckusick * Set parameters from open or stty into the DHU hardware 47337606Smarc * registers. Impossible values for speed or character 47437606Smarc * size are ignored and not copied back into tp. 47520976Smckusick */ 47637606Smarc dhuparam(tp, want) 47737606Smarc register struct tty *tp; 47837606Smarc register struct termios *want; 47920976Smckusick { 48037606Smarc register int unit = UNIT(tp->t_dev); 48137606Smarc register struct dhudevice *addr = (struct dhudevice *)tp->t_addr; 48220976Smckusick register int lpar; 48337606Smarc register long cflag; 48437606Smarc register int incode, outcode; 48520976Smckusick int s; 48637606Smarc 48720976Smckusick /* 48820976Smckusick * Block interrupts so parameters will be set 48920976Smckusick * before the line interrupts. 49020976Smckusick */ 49137606Smarc s = spltty(); 49237606Smarc 49337606Smarc if (want->c_ospeed == 0) { 49437606Smarc tp->t_ospeed = 0; 49537606Smarc tp->t_cflag |= HUPCL; 49620976Smckusick (void)dhumctl(unit, DHU_OFF, DMSET); 49720976Smckusick splx(s); 49820976Smckusick return; 49920976Smckusick } 50037606Smarc 50137606Smarc if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0) 50237606Smarc tp->t_ospeed = want->c_ospeed; 50337606Smarc else 50437606Smarc outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab); 50537606Smarc 50637606Smarc if (want->c_ispeed == 0) { 50737606Smarc tp->t_ispeed = 0; 50837606Smarc incode = outcode; 50937606Smarc } else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0) 51037606Smarc tp->t_ispeed = want->c_ispeed; 51137606Smarc else 51237606Smarc incode = ttspeedtab(tp->t_ispeed, dhuspeedtab); 51337606Smarc 51437606Smarc lpar = ((char)outcode<<12) | ((char)incode<<8); 51537606Smarc 51637606Smarc switch (want->c_cflag&CSIZE) { 51737606Smarc case CS6: case CS7: case CS8: 51837606Smarc tp->t_cflag = want->c_cflag; 51937606Smarc break; 52037606Smarc default: 52137606Smarc tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE); 52237606Smarc } 52337606Smarc cflag = tp->t_cflag; 52437606Smarc 52537606Smarc switch(cflag&CSIZE) { 52637606Smarc case CS6: 52737606Smarc lpar |= DHU_LP_BITS6; 52837606Smarc break; 52937606Smarc case CS7: 53037606Smarc lpar |= DHU_LP_BITS7; 53137606Smarc break; 53237606Smarc case CS8: 53320976Smckusick lpar |= DHU_LP_BITS8; 53437606Smarc break; 53537606Smarc } 53637606Smarc if (cflag&PARENB) { 53737606Smarc lpar |= DHU_LP_PENABLE; 53837606Smarc if ((cflag&PARODD) == 0) 53937606Smarc lpar |= DHU_LP_EPAR; 54037606Smarc } 54137606Smarc if (cflag&CSTOPB) 54237606Smarc lpar |= DHU_LP_TWOSB; 54337606Smarc 544*39061Smarc addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 54520976Smckusick addr->dhulpr = lpar; 54620976Smckusick splx(s); 54720976Smckusick } 54820976Smckusick 54920976Smckusick /* 55020976Smckusick * DHU11 transmitter interrupt. 55120976Smckusick * Restart each line which used to be active but has 55220976Smckusick * terminated transmission since the last interrupt. 55320976Smckusick */ 55420976Smckusick dhuxint(dhu) 55520976Smckusick int dhu; 55620976Smckusick { 55720976Smckusick register struct tty *tp; 55820976Smckusick register struct dhudevice *addr; 55920976Smckusick register struct tty *tp0; 56020976Smckusick register struct uba_device *ui; 56120976Smckusick register int line, t; 56220976Smckusick u_short cntr; 56320976Smckusick 56435401Stef #ifdef QBA 56527256Skridle (void) spl5(); 56627256Skridle #endif 56720976Smckusick ui = dhuinfo[dhu]; 56820976Smckusick tp0 = &dhu_tty[dhu<<4]; 56920976Smckusick addr = (struct dhudevice *)ui->ui_addr; 57020976Smckusick while ((t = addr->dhucsrh) & DHU_CSH_TI) { 57120976Smckusick line = DHU_TX_LINE(t); 57220976Smckusick tp = tp0 + line; 57320976Smckusick tp->t_state &= ~TS_BUSY; 57420976Smckusick if (t & DHU_CSH_NXM) { 57520976Smckusick printf("dhu(%d,%d): NXM fault\n", dhu, line); 57620976Smckusick /* SHOULD RESTART OR SOMETHING... */ 57720976Smckusick } 57820976Smckusick if (tp->t_state&TS_FLUSH) 57920976Smckusick tp->t_state &= ~TS_FLUSH; 58020976Smckusick else { 58120976Smckusick addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 58220976Smckusick /* 58320976Smckusick * Do arithmetic in a short to make up 58420976Smckusick * for lost 16&17 bits. 58520976Smckusick */ 58620976Smckusick cntr = addr->dhubar1 - 58720976Smckusick UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 58820976Smckusick ndflush(&tp->t_outq, (int)cntr); 58920976Smckusick } 59020976Smckusick if (tp->t_line) 59120976Smckusick (*linesw[tp->t_line].l_start)(tp); 59220976Smckusick else 59320976Smckusick dhustart(tp); 59420976Smckusick } 59520976Smckusick } 59620976Smckusick 59720976Smckusick /* 59820976Smckusick * Start (restart) transmission on the given DHU11 line. 59920976Smckusick */ 60020976Smckusick dhustart(tp) 60120976Smckusick register struct tty *tp; 60220976Smckusick { 60320976Smckusick register struct dhudevice *addr; 60420976Smckusick register int car, dhu, unit, nch; 60520976Smckusick int s; 60620976Smckusick 60720976Smckusick unit = minor(tp->t_dev); 60820976Smckusick dhu = unit >> 4; 60920976Smckusick unit &= 0xf; 61020976Smckusick addr = (struct dhudevice *)tp->t_addr; 61120976Smckusick 61220976Smckusick /* 61320976Smckusick * Must hold interrupts in following code to prevent 61420976Smckusick * state of the tp from changing. 61520976Smckusick */ 61620976Smckusick s = spl5(); 61720976Smckusick /* 61820976Smckusick * If it's currently active, or delaying, no need to do anything. 61920976Smckusick */ 62020976Smckusick if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 62120976Smckusick goto out; 62220976Smckusick /* 62320976Smckusick * If there are sleepers, and output has drained below low 62420976Smckusick * water mark, wake up the sleepers.. 62520976Smckusick */ 62637606Smarc if (tp->t_outq.c_cc <= tp->t_lowat) { 62720976Smckusick if (tp->t_state&TS_ASLEEP) { 62820976Smckusick tp->t_state &= ~TS_ASLEEP; 62920976Smckusick wakeup((caddr_t)&tp->t_outq); 63020976Smckusick } 63120976Smckusick if (tp->t_wsel) { 63220976Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 63320976Smckusick tp->t_wsel = 0; 63420976Smckusick tp->t_state &= ~TS_WCOLL; 63520976Smckusick } 63620976Smckusick } 63720976Smckusick /* 63820976Smckusick * Now restart transmission unless the output queue is 63920976Smckusick * empty. 64020976Smckusick */ 64120976Smckusick if (tp->t_outq.c_cc == 0) 64220976Smckusick goto out; 643*39061Smarc if (1 || !(tp->t_oflag & OPOST)) /*XXX*/ 64420976Smckusick nch = ndqb(&tp->t_outq, 0); 64520976Smckusick else { 64620976Smckusick nch = ndqb(&tp->t_outq, 0200); 64720976Smckusick /* 64820976Smckusick * If first thing on queue is a delay process it. 64920976Smckusick */ 65020976Smckusick if (nch == 0) { 65120976Smckusick nch = getc(&tp->t_outq); 65220976Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 65320976Smckusick tp->t_state |= TS_TIMEOUT; 65420976Smckusick goto out; 65520976Smckusick } 65620976Smckusick } 65720976Smckusick /* 65820976Smckusick * If characters to transmit, restart transmission. 65920976Smckusick */ 66020976Smckusick if (nch) { 66120976Smckusick car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 66220976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 66320976Smckusick addr->dhulcr &= ~DHU_LC_TXABORT; 66420976Smckusick addr->dhubcr = nch; 66520976Smckusick addr->dhubar1 = car; 66620976Smckusick addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 66720976Smckusick DHU_BA2_DMAGO; 66820976Smckusick tp->t_state |= TS_BUSY; 66920976Smckusick } 67020976Smckusick out: 67120976Smckusick splx(s); 67220976Smckusick } 67320976Smckusick 67420976Smckusick /* 67520976Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush. 67620976Smckusick */ 67720976Smckusick /*ARGSUSED*/ 67820976Smckusick dhustop(tp, flag) 67920976Smckusick register struct tty *tp; 68020976Smckusick { 68120976Smckusick register struct dhudevice *addr; 68220976Smckusick register int unit, s; 68320976Smckusick 68420976Smckusick addr = (struct dhudevice *)tp->t_addr; 68520976Smckusick /* 68620976Smckusick * Block input/output interrupts while messing with state. 68720976Smckusick */ 68820976Smckusick s = spl5(); 68920976Smckusick if (tp->t_state & TS_BUSY) { 69020976Smckusick /* 69120976Smckusick * Device is transmitting; stop output 69220976Smckusick * by selecting the line and setting the 69320976Smckusick * abort xmit bit. We will get an xmit interrupt, 69420976Smckusick * where we will figure out where to continue the 69520976Smckusick * next time the transmitter is enabled. If 69620976Smckusick * TS_FLUSH is set, the outq will be flushed. 69720976Smckusick * In either case, dhustart will clear the TXABORT bit. 69820976Smckusick */ 69920976Smckusick unit = minor(tp->t_dev); 70020976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 70120976Smckusick addr->dhulcr |= DHU_LC_TXABORT; 70220976Smckusick if ((tp->t_state&TS_TTSTOP)==0) 70320976Smckusick tp->t_state |= TS_FLUSH; 70420976Smckusick } 70520976Smckusick (void) splx(s); 70620976Smckusick } 70720976Smckusick 70820976Smckusick /* 70920976Smckusick * DHU11 modem control 71020976Smckusick */ 71120976Smckusick dhumctl(dev, bits, how) 71220976Smckusick dev_t dev; 71320976Smckusick int bits, how; 71420976Smckusick { 71520976Smckusick register struct dhudevice *dhuaddr; 71626291Skarels register int unit, mbits; 71720976Smckusick int s; 71820976Smckusick 71920976Smckusick unit = UNIT(dev); 72020976Smckusick dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 72120976Smckusick unit &= 0xf; 72220976Smckusick s = spl5(); 72320976Smckusick dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 72420976Smckusick /* 72520976Smckusick * combine byte from stat register (read only, bits 16..23) 72620976Smckusick * with lcr register (read write, bits 0..15). 72720976Smckusick */ 72820976Smckusick mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 72920976Smckusick switch (how) { 73020976Smckusick case DMSET: 73120976Smckusick mbits = (mbits & 0xff0000) | bits; 73220976Smckusick break; 73320976Smckusick 73420976Smckusick case DMBIS: 73520976Smckusick mbits |= bits; 73620976Smckusick break; 73720976Smckusick 73820976Smckusick case DMBIC: 73920976Smckusick mbits &= ~bits; 74020976Smckusick break; 74120976Smckusick 74220976Smckusick case DMGET: 74320976Smckusick (void) splx(s); 74420976Smckusick return(mbits); 74520976Smckusick } 74620976Smckusick dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 74720976Smckusick dhuaddr->dhulcr2 = DHU_LC2_TXEN; 74820976Smckusick (void) splx(s); 74920976Smckusick return(mbits); 75020976Smckusick } 75120976Smckusick 75220976Smckusick /* 75320976Smckusick * Reset state of driver if UBA reset was necessary. 75420976Smckusick * Reset the line and modem control registers. 75520976Smckusick * restart transmitters. 75620976Smckusick */ 75720976Smckusick dhureset(uban) 75820976Smckusick int uban; 75920976Smckusick { 76020976Smckusick register int dhu, unit; 76120976Smckusick register struct tty *tp; 76220976Smckusick register struct uba_device *ui; 76320976Smckusick register struct dhudevice *addr; 76420976Smckusick int i; 76520976Smckusick 76620976Smckusick for (dhu = 0; dhu < NDHU; dhu++) { 76720976Smckusick ui = dhuinfo[dhu]; 76820976Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 76920976Smckusick continue; 77020976Smckusick printf(" dhu%d", dhu); 77130322Skarels if (dhu_uballoc[uban] == dhu) { 77230322Skarels int info; 77330322Skarels 77430322Skarels info = uballoc(uban, (caddr_t)cfree, 77530322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 77630322Skarels if (info) 77730322Skarels cbase[uban] = UBAI_ADDR(info); 77830322Skarels else { 77930322Skarels printf(" [can't get uba map]"); 78030322Skarels cbase[uban] = -1; 78130322Skarels } 78225434Skarels } 78320976Smckusick addr = (struct dhudevice *)ui->ui_addr; 78420976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 78520976Smckusick addr->dhutimo = DHU_DEF_TIMO; 78620976Smckusick unit = dhu * 16; 78720976Smckusick for (i = 0; i < 16; i++) { 78820976Smckusick tp = &dhu_tty[unit]; 78920976Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 79037606Smarc dhuparam(tp, &tp->t_termios); 79120976Smckusick (void)dhumctl(unit, DHU_ON, DMSET); 79220976Smckusick tp->t_state &= ~TS_BUSY; 79320976Smckusick dhustart(tp); 79420976Smckusick } 79520976Smckusick unit++; 79620976Smckusick } 79720976Smckusick } 79820976Smckusick } 79920976Smckusick #endif 800