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*45804Sbostic * @(#)dhu.c 7.13 (Berkeley) 12/16/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 */ 22*45804Sbostic #include "../include/pte.h" 2320976Smckusick 24*45804Sbostic #include "sys/param.h" 25*45804Sbostic #include "sys/conf.h" 26*45804Sbostic #include "sys/user.h" 27*45804Sbostic #include "sys/proc.h" 28*45804Sbostic #include "sys/ioctl.h" 29*45804Sbostic #include "sys/tty.h" 30*45804Sbostic #include "sys/ttydefaults.h" 31*45804Sbostic #include "sys/map.h" 32*45804Sbostic #include "sys/buf.h" 33*45804Sbostic #include "sys/vm.h" 34*45804Sbostic #include "sys/kernel.h" 35*45804Sbostic #include "sys/syslog.h" 3620976Smckusick 3720976Smckusick #include "uba.h" 3820976Smckusick #include "ubareg.h" 3920976Smckusick #include "ubavar.h" 4020976Smckusick #include "dhureg.h" 4120976Smckusick 42*45804Sbostic #include "sys/bkmac.h" 43*45804Sbostic #include "sys/clist.h" 44*45804Sbostic #include "sys/file.h" 45*45804Sbostic #include "sys/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; 20040729Skarels 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) { 23544393Smarc tp->t_state |= TS_WOPEN; 23620976Smckusick ttychars(tp); 23720976Smckusick #ifndef PORTSELECTOR 23837606Smarc if (tp->t_ospeed == 0) { 23937606Smarc #endif 24037606Smarc tp->t_ispeed = SPEED; 24137606Smarc tp->t_ospeed = SPEED; 24237606Smarc ttsetwater(tp); 24337606Smarc tp->t_iflag = TTYDEF_IFLAG; 24437606Smarc tp->t_oflag = TTYDEF_OFLAG; 24537606Smarc tp->t_lflag = LFLAG; 24637606Smarc tp->t_cflag = TTYDEF_CFLAG; 24737606Smarc #ifdef PORTSELECTOR 24837606Smarc tp->t_cflag |= HUPCL; 24937606Smarc #else 25020976Smckusick } 25137606Smarc #endif 25220976Smckusick tp->t_dev = dev; 25337606Smarc dhuparam(tp, &tp->t_termios); 25420976Smckusick } 25520976Smckusick /* 25620976Smckusick * Wait for carrier, then process line discipline specific open. 25720976Smckusick */ 25837606Smarc s = spltty(); 25920976Smckusick if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 26020976Smckusick (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 26120976Smckusick tp->t_state |= TS_CARR_ON; 26240729Skarels while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 26340729Skarels (tp->t_state & TS_CARR_ON) == 0) { 26420976Smckusick tp->t_state |= TS_WOPEN; 26544393Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 26644393Smarc ttopen, 0)) 26740729Skarels break; 26820976Smckusick } 26920976Smckusick (void) splx(s); 27040729Skarels if (error) 27140729Skarels return (error); 27220976Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp)); 27320976Smckusick } 27420976Smckusick 27520976Smckusick /* 27620976Smckusick * Close a DHU11 line, turning off the modem control. 27720976Smckusick */ 27820976Smckusick /*ARGSUSED*/ 27920976Smckusick dhuclose(dev, flag) 28020976Smckusick dev_t dev; 28120976Smckusick int flag; 28220976Smckusick { 28320976Smckusick register struct tty *tp; 28420976Smckusick register unit; 28520976Smckusick 28620976Smckusick unit = UNIT(dev); 28720976Smckusick tp = &dhu_tty[unit]; 28820976Smckusick (*linesw[tp->t_line].l_close)(tp); 28920976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 29037606Smarc if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) || 29140729Skarels (tp->t_state&TS_ISOPEN) == 0) { 29220976Smckusick #ifdef PORTSELECTOR 29320976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 29420976Smckusick /* Hold DTR low for 0.5 seconds */ 29540729Skarels (void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2); 29620976Smckusick #else 29720976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 29820976Smckusick #endif PORTSELECTOR 29940729Skarels } 30040729Skarels return (ttyclose(tp)); 30120976Smckusick } 30220976Smckusick 30339061Smarc dhuread(dev, uio, flag) 30420976Smckusick dev_t dev; 30520976Smckusick struct uio *uio; 30620976Smckusick { 30720976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 30820976Smckusick 30939061Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 31020976Smckusick } 31120976Smckusick 31239061Smarc dhuwrite(dev, uio, flag) 31320976Smckusick dev_t dev; 31420976Smckusick struct uio *uio; 31520976Smckusick { 31620976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 31720976Smckusick 31839061Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 31920976Smckusick } 32020976Smckusick 32120976Smckusick /* 32220976Smckusick * DHU11 receiver interrupt. 32320976Smckusick */ 32420976Smckusick dhurint(dhu) 32520976Smckusick int dhu; 32620976Smckusick { 32720976Smckusick register struct tty *tp; 32837606Smarc register creg, c; 32920976Smckusick register struct dhudevice *addr; 33020976Smckusick register struct tty *tp0; 33120976Smckusick register struct uba_device *ui; 33220976Smckusick register line; 33320976Smckusick int overrun = 0; 33420976Smckusick 33535401Stef #ifdef QBA 33637606Smarc (void) spltty(); 33727256Skridle #endif 33820976Smckusick ui = dhuinfo[dhu]; 33920976Smckusick if (ui == 0 || ui->ui_alive == 0) 34020976Smckusick return; 34120976Smckusick addr = (struct dhudevice *)ui->ui_addr; 34220976Smckusick tp0 = &dhu_tty[dhu<<4]; 34320976Smckusick /* 34420976Smckusick * Loop fetching characters from the silo for this 34520976Smckusick * dhu until there are no more in the silo. 34620976Smckusick */ 34737606Smarc while ((creg = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 34837606Smarc line = DHU_RX_LINE(creg); 34920976Smckusick tp = tp0 + line; 35037606Smarc c = creg & 0xff; 35137606Smarc if ((creg & DHU_RB_STAT) == DHU_RB_STAT) { 35220976Smckusick /* 35320976Smckusick * modem changed or diag info 35420976Smckusick */ 35537606Smarc if (creg & DHU_RB_DIAG) { 35620976Smckusick /* decode diagnostic messages */ 35720976Smckusick continue; 35820976Smckusick } 35937606Smarc if (creg & DHU_ST_DCD) 36025395Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 36125395Skarels else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 36225395Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 36325395Skarels (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 36420976Smckusick continue; 36520976Smckusick } 36620976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 36720976Smckusick wakeup((caddr_t)&tp->t_rawq); 36820976Smckusick #ifdef PORTSELECTOR 36920976Smckusick if ((tp->t_state&TS_WOPEN) == 0) 37020976Smckusick #endif 37125395Skarels continue; 37220976Smckusick } 37339061Smarc if (creg & DHU_RB_PE) 37439061Smarc c |= TTY_PE; 37539061Smarc if (creg & DHU_RB_DO && overrun == 0) { 37639061Smarc log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 37739061Smarc overrun = 1; 37820976Smckusick } 37939061Smarc if (creg & DHU_RB_FE) 38039061Smarc c |= TTY_FE; 38137606Smarc 38239061Smarc (*linesw[tp->t_line].l_rint)(c, tp); 38320976Smckusick } 38420976Smckusick } 38520976Smckusick 38620976Smckusick /* 38720976Smckusick * Ioctl for DHU11. 38820976Smckusick */ 38920976Smckusick /*ARGSUSED*/ 39020976Smckusick dhuioctl(dev, cmd, data, flag) 39120976Smckusick caddr_t data; 39220976Smckusick { 39320976Smckusick register struct tty *tp; 39420976Smckusick register int unit = UNIT(dev); 39520976Smckusick int error; 39620976Smckusick 39720976Smckusick tp = &dhu_tty[unit]; 39820976Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 39920976Smckusick if (error >= 0) 40020976Smckusick return (error); 40120976Smckusick error = ttioctl(tp, cmd, data, flag); 40237606Smarc if (error >= 0) 40320976Smckusick return (error); 40420976Smckusick 40520976Smckusick switch (cmd) { 40620976Smckusick case TIOCSBRK: 40720976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIS); 40820976Smckusick break; 40920976Smckusick 41020976Smckusick case TIOCCBRK: 41120976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 41220976Smckusick break; 41320976Smckusick 41420976Smckusick case TIOCSDTR: 41520976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 41620976Smckusick break; 41720976Smckusick 41820976Smckusick case TIOCCDTR: 41920976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 42020976Smckusick break; 42120976Smckusick 42220976Smckusick case TIOCMSET: 42320976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 42420976Smckusick break; 42520976Smckusick 42620976Smckusick case TIOCMBIS: 42720976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 42820976Smckusick break; 42920976Smckusick 43020976Smckusick case TIOCMBIC: 43120976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 43220976Smckusick break; 43320976Smckusick 43420976Smckusick case TIOCMGET: 43520976Smckusick *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 43620976Smckusick break; 43720976Smckusick default: 43820976Smckusick return (ENOTTY); 43920976Smckusick } 44020976Smckusick return (0); 44120976Smckusick } 44220976Smckusick 44320976Smckusick dmtodhu(bits) 44420976Smckusick register int bits; 44520976Smckusick { 44620976Smckusick register int b = 0; 44720976Smckusick 44820976Smckusick if (bits & DML_RTS) b |= DHU_RTS; 44920976Smckusick if (bits & DML_DTR) b |= DHU_DTR; 45020976Smckusick if (bits & DML_LE) b |= DHU_LE; 45120976Smckusick return(b); 45220976Smckusick } 45320976Smckusick 45420976Smckusick dhutodm(bits) 45520976Smckusick register int bits; 45620976Smckusick { 45720976Smckusick register int b = 0; 45820976Smckusick 45920976Smckusick if (bits & DHU_DSR) b |= DML_DSR; 46020976Smckusick if (bits & DHU_RNG) b |= DML_RNG; 46120976Smckusick if (bits & DHU_CAR) b |= DML_CAR; 46220976Smckusick if (bits & DHU_CTS) b |= DML_CTS; 46320976Smckusick if (bits & DHU_RTS) b |= DML_RTS; 46420976Smckusick if (bits & DHU_DTR) b |= DML_DTR; 46520976Smckusick if (bits & DHU_LE) b |= DML_LE; 46620976Smckusick return(b); 46720976Smckusick } 46820976Smckusick 46920976Smckusick 47020976Smckusick /* 47120976Smckusick * Set parameters from open or stty into the DHU hardware 47237606Smarc * registers. Impossible values for speed or character 47337606Smarc * size are ignored and not copied back into tp. 47420976Smckusick */ 47537606Smarc dhuparam(tp, want) 47637606Smarc register struct tty *tp; 47737606Smarc register struct termios *want; 47820976Smckusick { 47937606Smarc register int unit = UNIT(tp->t_dev); 48037606Smarc register struct dhudevice *addr = (struct dhudevice *)tp->t_addr; 48120976Smckusick register int lpar; 48237606Smarc register long cflag; 48337606Smarc register int incode, outcode; 48420976Smckusick int s; 48537606Smarc 48620976Smckusick /* 48720976Smckusick * Block interrupts so parameters will be set 48820976Smckusick * before the line interrupts. 48920976Smckusick */ 49037606Smarc s = spltty(); 49137606Smarc 49237606Smarc if (want->c_ospeed == 0) { 49337606Smarc tp->t_ospeed = 0; 49437606Smarc tp->t_cflag |= HUPCL; 49520976Smckusick (void)dhumctl(unit, DHU_OFF, DMSET); 49620976Smckusick splx(s); 49720976Smckusick return; 49820976Smckusick } 49937606Smarc 50037606Smarc if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0) 50137606Smarc tp->t_ospeed = want->c_ospeed; 50237606Smarc else 50337606Smarc outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab); 50437606Smarc 50537606Smarc if (want->c_ispeed == 0) { 50637606Smarc tp->t_ispeed = 0; 50737606Smarc incode = outcode; 50837606Smarc } else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0) 50937606Smarc tp->t_ispeed = want->c_ispeed; 51037606Smarc else 51137606Smarc incode = ttspeedtab(tp->t_ispeed, dhuspeedtab); 51237606Smarc 51337606Smarc lpar = ((char)outcode<<12) | ((char)incode<<8); 51437606Smarc 51537606Smarc switch (want->c_cflag&CSIZE) { 51637606Smarc case CS6: case CS7: case CS8: 51737606Smarc tp->t_cflag = want->c_cflag; 51837606Smarc break; 51937606Smarc default: 52037606Smarc tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE); 52137606Smarc } 52237606Smarc cflag = tp->t_cflag; 52337606Smarc 52437606Smarc switch(cflag&CSIZE) { 52537606Smarc case CS6: 52637606Smarc lpar |= DHU_LP_BITS6; 52737606Smarc break; 52837606Smarc case CS7: 52937606Smarc lpar |= DHU_LP_BITS7; 53037606Smarc break; 53137606Smarc case CS8: 53220976Smckusick lpar |= DHU_LP_BITS8; 53337606Smarc break; 53437606Smarc } 53537606Smarc if (cflag&PARENB) { 53637606Smarc lpar |= DHU_LP_PENABLE; 53737606Smarc if ((cflag&PARODD) == 0) 53837606Smarc lpar |= DHU_LP_EPAR; 53937606Smarc } 54037606Smarc if (cflag&CSTOPB) 54137606Smarc lpar |= DHU_LP_TWOSB; 54237606Smarc 54339061Smarc addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 54420976Smckusick addr->dhulpr = lpar; 54520976Smckusick splx(s); 54620976Smckusick } 54720976Smckusick 54820976Smckusick /* 54920976Smckusick * DHU11 transmitter interrupt. 55020976Smckusick * Restart each line which used to be active but has 55120976Smckusick * terminated transmission since the last interrupt. 55220976Smckusick */ 55320976Smckusick dhuxint(dhu) 55420976Smckusick int dhu; 55520976Smckusick { 55620976Smckusick register struct tty *tp; 55720976Smckusick register struct dhudevice *addr; 55820976Smckusick register struct tty *tp0; 55920976Smckusick register struct uba_device *ui; 56020976Smckusick register int line, t; 56120976Smckusick u_short cntr; 56220976Smckusick 56335401Stef #ifdef QBA 56427256Skridle (void) spl5(); 56527256Skridle #endif 56620976Smckusick ui = dhuinfo[dhu]; 56720976Smckusick tp0 = &dhu_tty[dhu<<4]; 56820976Smckusick addr = (struct dhudevice *)ui->ui_addr; 56920976Smckusick while ((t = addr->dhucsrh) & DHU_CSH_TI) { 57020976Smckusick line = DHU_TX_LINE(t); 57120976Smckusick tp = tp0 + line; 57220976Smckusick tp->t_state &= ~TS_BUSY; 57320976Smckusick if (t & DHU_CSH_NXM) { 57420976Smckusick printf("dhu(%d,%d): NXM fault\n", dhu, line); 57520976Smckusick /* SHOULD RESTART OR SOMETHING... */ 57620976Smckusick } 57720976Smckusick if (tp->t_state&TS_FLUSH) 57820976Smckusick tp->t_state &= ~TS_FLUSH; 57920976Smckusick else { 58020976Smckusick addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 58120976Smckusick /* 58220976Smckusick * Do arithmetic in a short to make up 58320976Smckusick * for lost 16&17 bits. 58420976Smckusick */ 58520976Smckusick cntr = addr->dhubar1 - 58620976Smckusick UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 58720976Smckusick ndflush(&tp->t_outq, (int)cntr); 58820976Smckusick } 58920976Smckusick if (tp->t_line) 59020976Smckusick (*linesw[tp->t_line].l_start)(tp); 59120976Smckusick else 59220976Smckusick dhustart(tp); 59320976Smckusick } 59420976Smckusick } 59520976Smckusick 59620976Smckusick /* 59720976Smckusick * Start (restart) transmission on the given DHU11 line. 59820976Smckusick */ 59920976Smckusick dhustart(tp) 60020976Smckusick register struct tty *tp; 60120976Smckusick { 60220976Smckusick register struct dhudevice *addr; 60320976Smckusick register int car, dhu, unit, nch; 60420976Smckusick int s; 60520976Smckusick 60620976Smckusick unit = minor(tp->t_dev); 60720976Smckusick dhu = unit >> 4; 60820976Smckusick unit &= 0xf; 60920976Smckusick addr = (struct dhudevice *)tp->t_addr; 61020976Smckusick 61120976Smckusick /* 61220976Smckusick * Must hold interrupts in following code to prevent 61320976Smckusick * state of the tp from changing. 61420976Smckusick */ 61520976Smckusick s = spl5(); 61620976Smckusick /* 61720976Smckusick * If it's currently active, or delaying, no need to do anything. 61820976Smckusick */ 61920976Smckusick if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 62020976Smckusick goto out; 62120976Smckusick /* 62220976Smckusick * If there are sleepers, and output has drained below low 62320976Smckusick * water mark, wake up the sleepers.. 62420976Smckusick */ 62537606Smarc if (tp->t_outq.c_cc <= tp->t_lowat) { 62620976Smckusick if (tp->t_state&TS_ASLEEP) { 62720976Smckusick tp->t_state &= ~TS_ASLEEP; 62820976Smckusick wakeup((caddr_t)&tp->t_outq); 62920976Smckusick } 63020976Smckusick if (tp->t_wsel) { 63120976Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 63220976Smckusick tp->t_wsel = 0; 63320976Smckusick tp->t_state &= ~TS_WCOLL; 63420976Smckusick } 63520976Smckusick } 63620976Smckusick /* 63720976Smckusick * Now restart transmission unless the output queue is 63820976Smckusick * empty. 63920976Smckusick */ 64020976Smckusick if (tp->t_outq.c_cc == 0) 64120976Smckusick goto out; 64239061Smarc if (1 || !(tp->t_oflag & OPOST)) /*XXX*/ 64320976Smckusick nch = ndqb(&tp->t_outq, 0); 64420976Smckusick else { 64520976Smckusick nch = ndqb(&tp->t_outq, 0200); 64620976Smckusick /* 64720976Smckusick * If first thing on queue is a delay process it. 64820976Smckusick */ 64920976Smckusick if (nch == 0) { 65020976Smckusick nch = getc(&tp->t_outq); 65120976Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 65220976Smckusick tp->t_state |= TS_TIMEOUT; 65320976Smckusick goto out; 65420976Smckusick } 65520976Smckusick } 65620976Smckusick /* 65720976Smckusick * If characters to transmit, restart transmission. 65820976Smckusick */ 65920976Smckusick if (nch) { 66020976Smckusick car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 66120976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 66220976Smckusick addr->dhulcr &= ~DHU_LC_TXABORT; 66320976Smckusick addr->dhubcr = nch; 66420976Smckusick addr->dhubar1 = car; 66520976Smckusick addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 66620976Smckusick DHU_BA2_DMAGO; 66720976Smckusick tp->t_state |= TS_BUSY; 66820976Smckusick } 66920976Smckusick out: 67020976Smckusick splx(s); 67120976Smckusick } 67220976Smckusick 67320976Smckusick /* 67420976Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush. 67520976Smckusick */ 67620976Smckusick /*ARGSUSED*/ 67720976Smckusick dhustop(tp, flag) 67820976Smckusick register struct tty *tp; 67920976Smckusick { 68020976Smckusick register struct dhudevice *addr; 68120976Smckusick register int unit, s; 68220976Smckusick 68320976Smckusick addr = (struct dhudevice *)tp->t_addr; 68420976Smckusick /* 68520976Smckusick * Block input/output interrupts while messing with state. 68620976Smckusick */ 68720976Smckusick s = spl5(); 68820976Smckusick if (tp->t_state & TS_BUSY) { 68920976Smckusick /* 69020976Smckusick * Device is transmitting; stop output 69120976Smckusick * by selecting the line and setting the 69220976Smckusick * abort xmit bit. We will get an xmit interrupt, 69320976Smckusick * where we will figure out where to continue the 69420976Smckusick * next time the transmitter is enabled. If 69520976Smckusick * TS_FLUSH is set, the outq will be flushed. 69620976Smckusick * In either case, dhustart will clear the TXABORT bit. 69720976Smckusick */ 69820976Smckusick unit = minor(tp->t_dev); 69920976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 70020976Smckusick addr->dhulcr |= DHU_LC_TXABORT; 70120976Smckusick if ((tp->t_state&TS_TTSTOP)==0) 70220976Smckusick tp->t_state |= TS_FLUSH; 70320976Smckusick } 70420976Smckusick (void) splx(s); 70520976Smckusick } 70620976Smckusick 70720976Smckusick /* 70820976Smckusick * DHU11 modem control 70920976Smckusick */ 71020976Smckusick dhumctl(dev, bits, how) 71120976Smckusick dev_t dev; 71220976Smckusick int bits, how; 71320976Smckusick { 71420976Smckusick register struct dhudevice *dhuaddr; 71526291Skarels register int unit, mbits; 71620976Smckusick int s; 71720976Smckusick 71820976Smckusick unit = UNIT(dev); 71920976Smckusick dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 72020976Smckusick unit &= 0xf; 72120976Smckusick s = spl5(); 72220976Smckusick dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 72320976Smckusick /* 72420976Smckusick * combine byte from stat register (read only, bits 16..23) 72520976Smckusick * with lcr register (read write, bits 0..15). 72620976Smckusick */ 72720976Smckusick mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 72820976Smckusick switch (how) { 72920976Smckusick case DMSET: 73020976Smckusick mbits = (mbits & 0xff0000) | bits; 73120976Smckusick break; 73220976Smckusick 73320976Smckusick case DMBIS: 73420976Smckusick mbits |= bits; 73520976Smckusick break; 73620976Smckusick 73720976Smckusick case DMBIC: 73820976Smckusick mbits &= ~bits; 73920976Smckusick break; 74020976Smckusick 74120976Smckusick case DMGET: 74220976Smckusick (void) splx(s); 74320976Smckusick return(mbits); 74420976Smckusick } 74520976Smckusick dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 74620976Smckusick dhuaddr->dhulcr2 = DHU_LC2_TXEN; 74720976Smckusick (void) splx(s); 74820976Smckusick return(mbits); 74920976Smckusick } 75020976Smckusick 75120976Smckusick /* 75220976Smckusick * Reset state of driver if UBA reset was necessary. 75320976Smckusick * Reset the line and modem control registers. 75420976Smckusick * restart transmitters. 75520976Smckusick */ 75620976Smckusick dhureset(uban) 75720976Smckusick int uban; 75820976Smckusick { 75920976Smckusick register int dhu, unit; 76020976Smckusick register struct tty *tp; 76120976Smckusick register struct uba_device *ui; 76220976Smckusick register struct dhudevice *addr; 76320976Smckusick int i; 76420976Smckusick 76520976Smckusick for (dhu = 0; dhu < NDHU; dhu++) { 76620976Smckusick ui = dhuinfo[dhu]; 76720976Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 76820976Smckusick continue; 76920976Smckusick printf(" dhu%d", dhu); 77030322Skarels if (dhu_uballoc[uban] == dhu) { 77130322Skarels int info; 77230322Skarels 77330322Skarels info = uballoc(uban, (caddr_t)cfree, 77430322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 77530322Skarels if (info) 77630322Skarels cbase[uban] = UBAI_ADDR(info); 77730322Skarels else { 77830322Skarels printf(" [can't get uba map]"); 77930322Skarels cbase[uban] = -1; 78030322Skarels } 78125434Skarels } 78220976Smckusick addr = (struct dhudevice *)ui->ui_addr; 78320976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 78420976Smckusick addr->dhutimo = DHU_DEF_TIMO; 78520976Smckusick unit = dhu * 16; 78620976Smckusick for (i = 0; i < 16; i++) { 78720976Smckusick tp = &dhu_tty[unit]; 78820976Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 78937606Smarc dhuparam(tp, &tp->t_termios); 79020976Smckusick (void)dhumctl(unit, DHU_ON, DMSET); 79120976Smckusick tp->t_state &= ~TS_BUSY; 79220976Smckusick dhustart(tp); 79320976Smckusick } 79420976Smckusick unit++; 79520976Smckusick } 79620976Smckusick } 79720976Smckusick } 79820976Smckusick #endif 799