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*37606Smarc * @(#)dhu.c 7.6 (Berkeley) 05/01/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" 32*37606Smarc #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 63*37606Smarc #define SPEED TTYDEF_SPEED 64*37606Smarc #define LFLAG TTYDEF_LFLAG 6520976Smckusick #else 66*37606Smarc #define SPEED B4800 67*37606Smarc #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 */ 96*37606Smarc struct speedtab dhuspeedtab[] = { 97*37606Smarc 19200, 14, 98*37606Smarc 9600, 13, 99*37606Smarc 4800, 11, 100*37606Smarc 2400, 10, 101*37606Smarc 2000, 9, 102*37606Smarc 1800, 8, 103*37606Smarc 1200, 7, 104*37606Smarc 600, 6, 105*37606Smarc 300, 5, 106*37606Smarc 150, 4, 107*37606Smarc 134, 3, 108*37606Smarc 110, 2, 109*37606Smarc 75, 1, 110*37606Smarc 0, 0, 111*37606Smarc -1, -1, 112*37606Smarc }; 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; 20020976Smckusick int s; 201*37606Smarc 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; 213*37606Smarc 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 237*37606Smarc if (tp->t_ospeed == 0) { 238*37606Smarc #endif 239*37606Smarc tp->t_ispeed = SPEED; 240*37606Smarc tp->t_ospeed = SPEED; 241*37606Smarc ttsetwater(tp); 242*37606Smarc tp->t_iflag = TTYDEF_IFLAG; 243*37606Smarc tp->t_oflag = TTYDEF_OFLAG; 244*37606Smarc tp->t_lflag = LFLAG; 245*37606Smarc tp->t_cflag = TTYDEF_CFLAG; 246*37606Smarc #ifdef PORTSELECTOR 247*37606Smarc tp->t_cflag |= HUPCL; 248*37606Smarc #else 24920976Smckusick } 250*37606Smarc #endif 25120976Smckusick tp->t_dev = dev; 252*37606Smarc dhuparam(tp, &tp->t_termios); 25320976Smckusick } 25420976Smckusick /* 25520976Smckusick * Wait for carrier, then process line discipline specific open. 25620976Smckusick */ 257*37606Smarc s = spltty(); 25820976Smckusick if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 25920976Smckusick (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 26020976Smckusick tp->t_state |= TS_CARR_ON; 26120976Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 26220976Smckusick tp->t_state |= TS_WOPEN; 26320976Smckusick sleep((caddr_t)&tp->t_rawq, TTIPRI); 26420976Smckusick } 26520976Smckusick (void) splx(s); 26620976Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp)); 26720976Smckusick } 26820976Smckusick 26920976Smckusick /* 27020976Smckusick * Close a DHU11 line, turning off the modem control. 27120976Smckusick */ 27220976Smckusick /*ARGSUSED*/ 27320976Smckusick dhuclose(dev, flag) 27420976Smckusick dev_t dev; 27520976Smckusick int flag; 27620976Smckusick { 27720976Smckusick register struct tty *tp; 27820976Smckusick register unit; 27920976Smckusick 28020976Smckusick unit = UNIT(dev); 28120976Smckusick tp = &dhu_tty[unit]; 28220976Smckusick (*linesw[tp->t_line].l_close)(tp); 28320976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 284*37606Smarc if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) || 285*37606Smarc (tp->t_state&TS_ISOPEN)==0) 28620976Smckusick #ifdef PORTSELECTOR 28720976Smckusick { 28820976Smckusick extern int wakeup(); 28920976Smckusick 29020976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 29120976Smckusick /* Hold DTR low for 0.5 seconds */ 29220976Smckusick timeout(wakeup, (caddr_t) &tp->t_dev, hz/2); 29320976Smckusick sleep((caddr_t) &tp->t_dev, PZERO); 29420976Smckusick } 29520976Smckusick #else 29620976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 29720976Smckusick #endif PORTSELECTOR 29820976Smckusick ttyclose(tp); 29920976Smckusick } 30020976Smckusick 30120976Smckusick dhuread(dev, uio) 30220976Smckusick dev_t dev; 30320976Smckusick struct uio *uio; 30420976Smckusick { 30520976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 30620976Smckusick 30720976Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio)); 30820976Smckusick } 30920976Smckusick 31020976Smckusick dhuwrite(dev, uio) 31120976Smckusick dev_t dev; 31220976Smckusick struct uio *uio; 31320976Smckusick { 31420976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 31520976Smckusick 31620976Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio)); 31720976Smckusick } 31820976Smckusick 31920976Smckusick /* 32020976Smckusick * DHU11 receiver interrupt. 32120976Smckusick */ 32220976Smckusick dhurint(dhu) 32320976Smckusick int dhu; 32420976Smckusick { 32520976Smckusick register struct tty *tp; 326*37606Smarc register creg, c; 32720976Smckusick register struct dhudevice *addr; 32820976Smckusick register struct tty *tp0; 32920976Smckusick register struct uba_device *ui; 33020976Smckusick register line; 33120976Smckusick int overrun = 0; 33220976Smckusick 33335401Stef #ifdef QBA 334*37606Smarc (void) spltty(); 33527256Skridle #endif 33620976Smckusick ui = dhuinfo[dhu]; 33720976Smckusick if (ui == 0 || ui->ui_alive == 0) 33820976Smckusick return; 33920976Smckusick addr = (struct dhudevice *)ui->ui_addr; 34020976Smckusick tp0 = &dhu_tty[dhu<<4]; 34120976Smckusick /* 34220976Smckusick * Loop fetching characters from the silo for this 34320976Smckusick * dhu until there are no more in the silo. 34420976Smckusick */ 345*37606Smarc while ((creg = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 346*37606Smarc line = DHU_RX_LINE(creg); 34720976Smckusick tp = tp0 + line; 348*37606Smarc c = creg & 0xff; 349*37606Smarc if ((creg & DHU_RB_STAT) == DHU_RB_STAT) { 35020976Smckusick /* 35120976Smckusick * modem changed or diag info 35220976Smckusick */ 353*37606Smarc if (creg & DHU_RB_DIAG) { 35420976Smckusick /* decode diagnostic messages */ 35520976Smckusick continue; 35620976Smckusick } 357*37606Smarc if (creg & DHU_ST_DCD) 35825395Skarels (void)(*linesw[tp->t_line].l_modem)(tp, 1); 35925395Skarels else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 36025395Skarels (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 36125395Skarels (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 36220976Smckusick continue; 36320976Smckusick } 36420976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 36520976Smckusick wakeup((caddr_t)&tp->t_rawq); 36620976Smckusick #ifdef PORTSELECTOR 36720976Smckusick if ((tp->t_state&TS_WOPEN) == 0) 36820976Smckusick #endif 36925395Skarels continue; 37020976Smckusick } 371*37606Smarc #ifdef COMPAT_43 372*37606Smarc if (tp->t_line != POSXDISC) { 373*37606Smarc if (creg & DHU_RB_PE) 374*37606Smarc if ((tp->t_flags&(EVENP|ODDP)) == EVENP || 375*37606Smarc (tp->t_flags&(EVENP|ODDP)) == ODDP) 376*37606Smarc continue; 377*37606Smarc if ((creg & DHU_RB_DO) && overrun == 0) { 378*37606Smarc log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 379*37606Smarc overrun = 1; 380*37606Smarc } 381*37606Smarc if (creg & DHU_RB_FE) 382*37606Smarc /* 383*37606Smarc * At framing error (break) generate 384*37606Smarc * a null (in raw mode, for getty), or a 385*37606Smarc * interrupt (in cooked/cbreak mode). 386*37606Smarc */ 387*37606Smarc if (tp->t_flags&RAW) 388*37606Smarc c = 0; 389*37606Smarc else 390*37606Smarc c = tp->t_intrc; 391*37606Smarc } else { 392*37606Smarc #endif /*COMPAT_43*/ 393*37606Smarc if (creg & DHU_RB_PE) 394*37606Smarc c |= TTY_PE; 395*37606Smarc if (creg & DHU_RB_DO && overrun == 0) { 396*37606Smarc log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 397*37606Smarc overrun = 1; 398*37606Smarc } 399*37606Smarc if (creg & DHU_RB_FE) 400*37606Smarc c |= TTY_FE; 401*37606Smarc #ifdef COMPAT_43 40220976Smckusick } 403*37606Smarc #endif 404*37606Smarc 40520976Smckusick #if NBK > 0 40620976Smckusick if (tp->t_line == NETLDISC) { 40720976Smckusick c &= 0x7f; 40820976Smckusick BKINPUT(c, tp); 40920976Smckusick } else 41020976Smckusick #endif 41120976Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 41220976Smckusick } 41320976Smckusick } 41420976Smckusick 41520976Smckusick /* 41620976Smckusick * Ioctl for DHU11. 41720976Smckusick */ 41820976Smckusick /*ARGSUSED*/ 41920976Smckusick dhuioctl(dev, cmd, data, flag) 42020976Smckusick caddr_t data; 42120976Smckusick { 42220976Smckusick register struct tty *tp; 42320976Smckusick register int unit = UNIT(dev); 42420976Smckusick int error; 42520976Smckusick 42620976Smckusick tp = &dhu_tty[unit]; 42720976Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 42820976Smckusick if (error >= 0) 42920976Smckusick return (error); 43020976Smckusick error = ttioctl(tp, cmd, data, flag); 431*37606Smarc if (error >= 0) 43220976Smckusick return (error); 43320976Smckusick 43420976Smckusick switch (cmd) { 43520976Smckusick case TIOCSBRK: 43620976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIS); 43720976Smckusick break; 43820976Smckusick 43920976Smckusick case TIOCCBRK: 44020976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 44120976Smckusick break; 44220976Smckusick 44320976Smckusick case TIOCSDTR: 44420976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 44520976Smckusick break; 44620976Smckusick 44720976Smckusick case TIOCCDTR: 44820976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 44920976Smckusick break; 45020976Smckusick 45120976Smckusick case TIOCMSET: 45220976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 45320976Smckusick break; 45420976Smckusick 45520976Smckusick case TIOCMBIS: 45620976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 45720976Smckusick break; 45820976Smckusick 45920976Smckusick case TIOCMBIC: 46020976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 46120976Smckusick break; 46220976Smckusick 46320976Smckusick case TIOCMGET: 46420976Smckusick *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 46520976Smckusick break; 46620976Smckusick default: 46720976Smckusick return (ENOTTY); 46820976Smckusick } 46920976Smckusick return (0); 47020976Smckusick } 47120976Smckusick 47220976Smckusick dmtodhu(bits) 47320976Smckusick register int bits; 47420976Smckusick { 47520976Smckusick register int b = 0; 47620976Smckusick 47720976Smckusick if (bits & DML_RTS) b |= DHU_RTS; 47820976Smckusick if (bits & DML_DTR) b |= DHU_DTR; 47920976Smckusick if (bits & DML_LE) b |= DHU_LE; 48020976Smckusick return(b); 48120976Smckusick } 48220976Smckusick 48320976Smckusick dhutodm(bits) 48420976Smckusick register int bits; 48520976Smckusick { 48620976Smckusick register int b = 0; 48720976Smckusick 48820976Smckusick if (bits & DHU_DSR) b |= DML_DSR; 48920976Smckusick if (bits & DHU_RNG) b |= DML_RNG; 49020976Smckusick if (bits & DHU_CAR) b |= DML_CAR; 49120976Smckusick if (bits & DHU_CTS) b |= DML_CTS; 49220976Smckusick if (bits & DHU_RTS) b |= DML_RTS; 49320976Smckusick if (bits & DHU_DTR) b |= DML_DTR; 49420976Smckusick if (bits & DHU_LE) b |= DML_LE; 49520976Smckusick return(b); 49620976Smckusick } 49720976Smckusick 49820976Smckusick 49920976Smckusick /* 50020976Smckusick * Set parameters from open or stty into the DHU hardware 501*37606Smarc * registers. Impossible values for speed or character 502*37606Smarc * size are ignored and not copied back into tp. 50320976Smckusick */ 504*37606Smarc dhuparam(tp, want) 505*37606Smarc register struct tty *tp; 506*37606Smarc register struct termios *want; 50720976Smckusick { 508*37606Smarc register int unit = UNIT(tp->t_dev); 509*37606Smarc register struct dhudevice *addr = (struct dhudevice *)tp->t_addr; 51020976Smckusick register int lpar; 511*37606Smarc register long cflag; 512*37606Smarc register int incode, outcode; 51320976Smckusick int s; 514*37606Smarc 51520976Smckusick /* 51620976Smckusick * Block interrupts so parameters will be set 51720976Smckusick * before the line interrupts. 51820976Smckusick */ 519*37606Smarc s = spltty(); 520*37606Smarc 521*37606Smarc if (want->c_ospeed == 0) { 522*37606Smarc tp->t_ospeed = 0; 523*37606Smarc tp->t_cflag |= HUPCL; 52420976Smckusick (void)dhumctl(unit, DHU_OFF, DMSET); 52520976Smckusick splx(s); 52620976Smckusick return; 52720976Smckusick } 528*37606Smarc 529*37606Smarc if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0) 530*37606Smarc tp->t_ospeed = want->c_ospeed; 531*37606Smarc else 532*37606Smarc outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab); 533*37606Smarc 534*37606Smarc if (want->c_ispeed == 0) { 535*37606Smarc tp->t_ispeed = 0; 536*37606Smarc incode = outcode; 537*37606Smarc } else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0) 538*37606Smarc tp->t_ispeed = want->c_ispeed; 539*37606Smarc else 540*37606Smarc incode = ttspeedtab(tp->t_ispeed, dhuspeedtab); 541*37606Smarc 542*37606Smarc lpar = ((char)outcode<<12) | ((char)incode<<8); 543*37606Smarc 544*37606Smarc switch (want->c_cflag&CSIZE) { 545*37606Smarc case CS6: case CS7: case CS8: 546*37606Smarc tp->t_cflag = want->c_cflag; 547*37606Smarc break; 548*37606Smarc default: 549*37606Smarc tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE); 550*37606Smarc } 551*37606Smarc cflag = tp->t_cflag; 552*37606Smarc 553*37606Smarc switch(cflag&CSIZE) { 554*37606Smarc case CS6: 555*37606Smarc lpar |= DHU_LP_BITS6; 556*37606Smarc break; 557*37606Smarc case CS7: 558*37606Smarc lpar |= DHU_LP_BITS7; 559*37606Smarc break; 560*37606Smarc case CS8: 56120976Smckusick lpar |= DHU_LP_BITS8; 562*37606Smarc break; 563*37606Smarc } 564*37606Smarc if (cflag&PARENB) { 565*37606Smarc lpar |= DHU_LP_PENABLE; 566*37606Smarc if ((cflag&PARODD) == 0) 567*37606Smarc lpar |= DHU_LP_EPAR; 568*37606Smarc } 569*37606Smarc if (cflag&CSTOPB) 570*37606Smarc lpar |= DHU_LP_TWOSB; 571*37606Smarc if (cflag&CREAD) 572*37606Smarc addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 57320976Smckusick else 574*37606Smarc addr->dhucsr = DHU_SELECT(unit) | DHU_CS_TIE; 575*37606Smarc 57620976Smckusick addr->dhulpr = lpar; 57720976Smckusick splx(s); 57820976Smckusick } 57920976Smckusick 58020976Smckusick /* 58120976Smckusick * DHU11 transmitter interrupt. 58220976Smckusick * Restart each line which used to be active but has 58320976Smckusick * terminated transmission since the last interrupt. 58420976Smckusick */ 58520976Smckusick dhuxint(dhu) 58620976Smckusick int dhu; 58720976Smckusick { 58820976Smckusick register struct tty *tp; 58920976Smckusick register struct dhudevice *addr; 59020976Smckusick register struct tty *tp0; 59120976Smckusick register struct uba_device *ui; 59220976Smckusick register int line, t; 59320976Smckusick u_short cntr; 59420976Smckusick 59535401Stef #ifdef QBA 59627256Skridle (void) spl5(); 59727256Skridle #endif 59820976Smckusick ui = dhuinfo[dhu]; 59920976Smckusick tp0 = &dhu_tty[dhu<<4]; 60020976Smckusick addr = (struct dhudevice *)ui->ui_addr; 60120976Smckusick while ((t = addr->dhucsrh) & DHU_CSH_TI) { 60220976Smckusick line = DHU_TX_LINE(t); 60320976Smckusick tp = tp0 + line; 60420976Smckusick tp->t_state &= ~TS_BUSY; 60520976Smckusick if (t & DHU_CSH_NXM) { 60620976Smckusick printf("dhu(%d,%d): NXM fault\n", dhu, line); 60720976Smckusick /* SHOULD RESTART OR SOMETHING... */ 60820976Smckusick } 60920976Smckusick if (tp->t_state&TS_FLUSH) 61020976Smckusick tp->t_state &= ~TS_FLUSH; 61120976Smckusick else { 61220976Smckusick addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 61320976Smckusick /* 61420976Smckusick * Do arithmetic in a short to make up 61520976Smckusick * for lost 16&17 bits. 61620976Smckusick */ 61720976Smckusick cntr = addr->dhubar1 - 61820976Smckusick UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 61920976Smckusick ndflush(&tp->t_outq, (int)cntr); 62020976Smckusick } 62120976Smckusick if (tp->t_line) 62220976Smckusick (*linesw[tp->t_line].l_start)(tp); 62320976Smckusick else 62420976Smckusick dhustart(tp); 62520976Smckusick } 62620976Smckusick } 62720976Smckusick 62820976Smckusick /* 62920976Smckusick * Start (restart) transmission on the given DHU11 line. 63020976Smckusick */ 63120976Smckusick dhustart(tp) 63220976Smckusick register struct tty *tp; 63320976Smckusick { 63420976Smckusick register struct dhudevice *addr; 63520976Smckusick register int car, dhu, unit, nch; 63620976Smckusick int s; 63720976Smckusick 63820976Smckusick unit = minor(tp->t_dev); 63920976Smckusick dhu = unit >> 4; 64020976Smckusick unit &= 0xf; 64120976Smckusick addr = (struct dhudevice *)tp->t_addr; 64220976Smckusick 64320976Smckusick /* 64420976Smckusick * Must hold interrupts in following code to prevent 64520976Smckusick * state of the tp from changing. 64620976Smckusick */ 64720976Smckusick s = spl5(); 64820976Smckusick /* 64920976Smckusick * If it's currently active, or delaying, no need to do anything. 65020976Smckusick */ 65120976Smckusick if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 65220976Smckusick goto out; 65320976Smckusick /* 65420976Smckusick * If there are sleepers, and output has drained below low 65520976Smckusick * water mark, wake up the sleepers.. 65620976Smckusick */ 657*37606Smarc if (tp->t_outq.c_cc <= tp->t_lowat) { 65820976Smckusick if (tp->t_state&TS_ASLEEP) { 65920976Smckusick tp->t_state &= ~TS_ASLEEP; 66020976Smckusick wakeup((caddr_t)&tp->t_outq); 66120976Smckusick } 66220976Smckusick if (tp->t_wsel) { 66320976Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 66420976Smckusick tp->t_wsel = 0; 66520976Smckusick tp->t_state &= ~TS_WCOLL; 66620976Smckusick } 66720976Smckusick } 66820976Smckusick /* 66920976Smckusick * Now restart transmission unless the output queue is 67020976Smckusick * empty. 67120976Smckusick */ 67220976Smckusick if (tp->t_outq.c_cc == 0) 67320976Smckusick goto out; 674*37606Smarc if (!(tp->t_oflag & OPOST)) 67520976Smckusick nch = ndqb(&tp->t_outq, 0); 67620976Smckusick else { 67720976Smckusick nch = ndqb(&tp->t_outq, 0200); 67820976Smckusick /* 67920976Smckusick * If first thing on queue is a delay process it. 68020976Smckusick */ 68120976Smckusick if (nch == 0) { 68220976Smckusick nch = getc(&tp->t_outq); 68320976Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 68420976Smckusick tp->t_state |= TS_TIMEOUT; 68520976Smckusick goto out; 68620976Smckusick } 68720976Smckusick } 68820976Smckusick /* 68920976Smckusick * If characters to transmit, restart transmission. 69020976Smckusick */ 69120976Smckusick if (nch) { 69220976Smckusick car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 69320976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 69420976Smckusick addr->dhulcr &= ~DHU_LC_TXABORT; 69520976Smckusick addr->dhubcr = nch; 69620976Smckusick addr->dhubar1 = car; 69720976Smckusick addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 69820976Smckusick DHU_BA2_DMAGO; 69920976Smckusick tp->t_state |= TS_BUSY; 70020976Smckusick } 70120976Smckusick out: 70220976Smckusick splx(s); 70320976Smckusick } 70420976Smckusick 70520976Smckusick /* 70620976Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush. 70720976Smckusick */ 70820976Smckusick /*ARGSUSED*/ 70920976Smckusick dhustop(tp, flag) 71020976Smckusick register struct tty *tp; 71120976Smckusick { 71220976Smckusick register struct dhudevice *addr; 71320976Smckusick register int unit, s; 71420976Smckusick 71520976Smckusick addr = (struct dhudevice *)tp->t_addr; 71620976Smckusick /* 71720976Smckusick * Block input/output interrupts while messing with state. 71820976Smckusick */ 71920976Smckusick s = spl5(); 72020976Smckusick if (tp->t_state & TS_BUSY) { 72120976Smckusick /* 72220976Smckusick * Device is transmitting; stop output 72320976Smckusick * by selecting the line and setting the 72420976Smckusick * abort xmit bit. We will get an xmit interrupt, 72520976Smckusick * where we will figure out where to continue the 72620976Smckusick * next time the transmitter is enabled. If 72720976Smckusick * TS_FLUSH is set, the outq will be flushed. 72820976Smckusick * In either case, dhustart will clear the TXABORT bit. 72920976Smckusick */ 73020976Smckusick unit = minor(tp->t_dev); 73120976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 73220976Smckusick addr->dhulcr |= DHU_LC_TXABORT; 73320976Smckusick if ((tp->t_state&TS_TTSTOP)==0) 73420976Smckusick tp->t_state |= TS_FLUSH; 73520976Smckusick } 73620976Smckusick (void) splx(s); 73720976Smckusick } 73820976Smckusick 73920976Smckusick /* 74020976Smckusick * DHU11 modem control 74120976Smckusick */ 74220976Smckusick dhumctl(dev, bits, how) 74320976Smckusick dev_t dev; 74420976Smckusick int bits, how; 74520976Smckusick { 74620976Smckusick register struct dhudevice *dhuaddr; 74726291Skarels register int unit, mbits; 74820976Smckusick int s; 74920976Smckusick 75020976Smckusick unit = UNIT(dev); 75120976Smckusick dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 75220976Smckusick unit &= 0xf; 75320976Smckusick s = spl5(); 75420976Smckusick dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 75520976Smckusick /* 75620976Smckusick * combine byte from stat register (read only, bits 16..23) 75720976Smckusick * with lcr register (read write, bits 0..15). 75820976Smckusick */ 75920976Smckusick mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 76020976Smckusick switch (how) { 76120976Smckusick case DMSET: 76220976Smckusick mbits = (mbits & 0xff0000) | bits; 76320976Smckusick break; 76420976Smckusick 76520976Smckusick case DMBIS: 76620976Smckusick mbits |= bits; 76720976Smckusick break; 76820976Smckusick 76920976Smckusick case DMBIC: 77020976Smckusick mbits &= ~bits; 77120976Smckusick break; 77220976Smckusick 77320976Smckusick case DMGET: 77420976Smckusick (void) splx(s); 77520976Smckusick return(mbits); 77620976Smckusick } 77720976Smckusick dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 77820976Smckusick dhuaddr->dhulcr2 = DHU_LC2_TXEN; 77920976Smckusick (void) splx(s); 78020976Smckusick return(mbits); 78120976Smckusick } 78220976Smckusick 78320976Smckusick /* 78420976Smckusick * Reset state of driver if UBA reset was necessary. 78520976Smckusick * Reset the line and modem control registers. 78620976Smckusick * restart transmitters. 78720976Smckusick */ 78820976Smckusick dhureset(uban) 78920976Smckusick int uban; 79020976Smckusick { 79120976Smckusick register int dhu, unit; 79220976Smckusick register struct tty *tp; 79320976Smckusick register struct uba_device *ui; 79420976Smckusick register struct dhudevice *addr; 79520976Smckusick int i; 79620976Smckusick 79720976Smckusick for (dhu = 0; dhu < NDHU; dhu++) { 79820976Smckusick ui = dhuinfo[dhu]; 79920976Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 80020976Smckusick continue; 80120976Smckusick printf(" dhu%d", dhu); 80230322Skarels if (dhu_uballoc[uban] == dhu) { 80330322Skarels int info; 80430322Skarels 80530322Skarels info = uballoc(uban, (caddr_t)cfree, 80630322Skarels nclist * sizeof(struct cblock), UBA_CANTWAIT); 80730322Skarels if (info) 80830322Skarels cbase[uban] = UBAI_ADDR(info); 80930322Skarels else { 81030322Skarels printf(" [can't get uba map]"); 81130322Skarels cbase[uban] = -1; 81230322Skarels } 81325434Skarels } 81420976Smckusick addr = (struct dhudevice *)ui->ui_addr; 81520976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 81620976Smckusick addr->dhutimo = DHU_DEF_TIMO; 81720976Smckusick unit = dhu * 16; 81820976Smckusick for (i = 0; i < 16; i++) { 81920976Smckusick tp = &dhu_tty[unit]; 82020976Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 821*37606Smarc dhuparam(tp, &tp->t_termios); 82220976Smckusick (void)dhumctl(unit, DHU_ON, DMSET); 82320976Smckusick tp->t_state &= ~TS_BUSY; 82420976Smckusick dhustart(tp); 82520976Smckusick } 82620976Smckusick unit++; 82720976Smckusick } 82820976Smckusick } 82920976Smckusick } 83020976Smckusick #endif 831