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