1*20976Smckusick /* dhu.c 4.1 85/05/20 */ 2*20976Smckusick 3*20976Smckusick /* 4*20976Smckusick * based on dh.c 6.3 84/03/15 5*20976Smckusick * and on dmf.c 6.2 84/02/16 6*20976Smckusick * 7*20976Smckusick * Dave Johnson, Brown University Computer Science 8*20976Smckusick * ddj%brown@csnet-relay 9*20976Smckusick */ 10*20976Smckusick 11*20976Smckusick #include "dhu.h" 12*20976Smckusick #if NDHU > 0 13*20976Smckusick /* 14*20976Smckusick * DHU-11 driver 15*20976Smckusick */ 16*20976Smckusick #include "../machine/pte.h" 17*20976Smckusick 18*20976Smckusick #include "bk.h" 19*20976Smckusick #include "param.h" 20*20976Smckusick #include "conf.h" 21*20976Smckusick #include "dir.h" 22*20976Smckusick #include "user.h" 23*20976Smckusick #include "proc.h" 24*20976Smckusick #include "ioctl.h" 25*20976Smckusick #include "tty.h" 26*20976Smckusick #include "map.h" 27*20976Smckusick #include "buf.h" 28*20976Smckusick #include "vm.h" 29*20976Smckusick #include "kernel.h" 30*20976Smckusick #include "syslog.h" 31*20976Smckusick 32*20976Smckusick #include "uba.h" 33*20976Smckusick #include "ubareg.h" 34*20976Smckusick #include "ubavar.h" 35*20976Smckusick #include "dhureg.h" 36*20976Smckusick 37*20976Smckusick #include "bkmac.h" 38*20976Smckusick #include "clist.h" 39*20976Smckusick #include "file.h" 40*20976Smckusick #include "uio.h" 41*20976Smckusick 42*20976Smckusick /* 43*20976Smckusick * Definition of the driver for the auto-configuration program. 44*20976Smckusick */ 45*20976Smckusick int dhuprobe(), dhuattach(), dhurint(), dhuxint(); 46*20976Smckusick struct uba_device *dhuinfo[NDHU]; 47*20976Smckusick u_short dhustd[] = { 160440, 160500 }; /* some common addresses */ 48*20976Smckusick struct uba_driver dhudriver = 49*20976Smckusick { dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo }; 50*20976Smckusick 51*20976Smckusick #define NDHULINE (NDHU*16) 52*20976Smckusick 53*20976Smckusick #define UNIT(x) (minor(x)) 54*20976Smckusick 55*20976Smckusick #ifndef PORTSELECTOR 56*20976Smckusick #define ISPEED B300 57*20976Smckusick #define IFLAGS (EVENP|ODDP|ECHO) 58*20976Smckusick #else 59*20976Smckusick #define ISPEED B4800 60*20976Smckusick #define IFLAGS (EVENP|ODDP) 61*20976Smckusick #endif 62*20976Smckusick 63*20976Smckusick /* 64*20976Smckusick * default receive silo timeout value -- valid values are 2..255 65*20976Smckusick * number of ms. to delay between first char received and receive interrupt 66*20976Smckusick * 67*20976Smckusick * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0 68*20976Smckusick */ 69*20976Smckusick #define DHU_DEF_TIMO 20 70*20976Smckusick 71*20976Smckusick /* 72*20976Smckusick * Other values for silo timeout register defined here but not used: 73*20976Smckusick * receive interrupt only on modem control or silo alarm (3/4 full) 74*20976Smckusick */ 75*20976Smckusick #define DHU_POLL_TIMO 0 76*20976Smckusick /* 77*20976Smckusick * receive interrupt immediately on receive character 78*20976Smckusick */ 79*20976Smckusick #define DHU_NO_TIMO 1 80*20976Smckusick 81*20976Smckusick /* 82*20976Smckusick * Local variables for the driver 83*20976Smckusick */ 84*20976Smckusick /* 85*20976Smckusick * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B". 86*20976Smckusick * EXTA => 19200 baud 87*20976Smckusick * EXTB => 2000 baud 88*20976Smckusick */ 89*20976Smckusick char dhu_speeds[] = 90*20976Smckusick { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 10, 11, 13, 14, 9 }; 91*20976Smckusick 92*20976Smckusick short dhusoftCAR[NDHU]; 93*20976Smckusick 94*20976Smckusick struct tty dhu_tty[NDHULINE]; 95*20976Smckusick int ndhu = NDHULINE; 96*20976Smckusick int dhuact; /* mask of active dhu's */ 97*20976Smckusick int dhustart(), ttrstrt(); 98*20976Smckusick 99*20976Smckusick /* 100*20976Smckusick * The clist space is mapped by the driver onto each UNIBUS. 101*20976Smckusick * The UBACVT macro converts a clist space address for unibus uban 102*20976Smckusick * into an i/o space address for the DMA routine. 103*20976Smckusick */ 104*20976Smckusick int dhu_ubinfo[NUBA]; /* info about allocated unibus map */ 105*20976Smckusick static int cbase[NUBA]; /* base address in unibus map */ 106*20976Smckusick #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 107*20976Smckusick 108*20976Smckusick /* 109*20976Smckusick * Routine for configuration to force a dhu to interrupt. 110*20976Smckusick */ 111*20976Smckusick /*ARGSUSED*/ 112*20976Smckusick dhuprobe(reg) 113*20976Smckusick caddr_t reg; 114*20976Smckusick { 115*20976Smckusick register int br, cvec; /* these are ``value-result'' */ 116*20976Smckusick register struct dhudevice *dhuaddr = (struct dhudevice *)reg; 117*20976Smckusick int i; 118*20976Smckusick 119*20976Smckusick #ifdef lint 120*20976Smckusick br = 0; cvec = br; br = cvec; 121*20976Smckusick if (ndhu == 0) ndhu = 1; 122*20976Smckusick dhurint(0); dhuxint(0); 123*20976Smckusick #endif 124*20976Smckusick /* 125*20976Smckusick * The basic idea here is: 126*20976Smckusick * do a self-test by setting the Master-Reset bit 127*20976Smckusick * if this fails, then return 128*20976Smckusick * if successful, there will be 8 diagnostic codes in RX FIFO 129*20976Smckusick * therefore ask for a Received-Data-Available interrupt 130*20976Smckusick * wait for it... 131*20976Smckusick * reset the interrupt-enable bit and flush out the diag. codes 132*20976Smckusick */ 133*20976Smckusick dhuaddr->dhucsr = DHU_CS_MCLR; 134*20976Smckusick for (i = 0; i < 1000; i++) { 135*20976Smckusick DELAY(10000); 136*20976Smckusick if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0) 137*20976Smckusick break; 138*20976Smckusick } 139*20976Smckusick if (dhuaddr->dhucsr&DHU_CS_MCLR) 140*20976Smckusick return(0); 141*20976Smckusick if (dhuaddr->dhucsr&DHU_CS_DFAIL) 142*20976Smckusick return(0); 143*20976Smckusick dhuaddr->dhucsr = DHU_CS_RIE; 144*20976Smckusick DELAY(1000); 145*20976Smckusick dhuaddr->dhucsr = 0; 146*20976Smckusick while (dhuaddr->dhurbuf < 0) 147*20976Smckusick /* void */; 148*20976Smckusick return (sizeof(struct dhudevice)); 149*20976Smckusick } 150*20976Smckusick 151*20976Smckusick /* 152*20976Smckusick * Routine called to attach a dhu. 153*20976Smckusick */ 154*20976Smckusick dhuattach(ui) 155*20976Smckusick struct uba_device *ui; 156*20976Smckusick { 157*20976Smckusick 158*20976Smckusick dhusoftCAR[ui->ui_unit] = ui->ui_flags; 159*20976Smckusick } 160*20976Smckusick 161*20976Smckusick /* 162*20976Smckusick * Open a DHU11 line, mapping the clist onto the uba if this 163*20976Smckusick * is the first dhu on this uba. Turn on this dhu if this is 164*20976Smckusick * the first use of it. 165*20976Smckusick */ 166*20976Smckusick /*ARGSUSED*/ 167*20976Smckusick dhuopen(dev, flag) 168*20976Smckusick dev_t dev; 169*20976Smckusick { 170*20976Smckusick register struct tty *tp; 171*20976Smckusick register int unit, dhu; 172*20976Smckusick register struct dhudevice *addr; 173*20976Smckusick register struct uba_device *ui; 174*20976Smckusick int s; 175*20976Smckusick 176*20976Smckusick unit = UNIT(dev); 177*20976Smckusick dhu = unit >> 4; 178*20976Smckusick if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0) 179*20976Smckusick return (ENXIO); 180*20976Smckusick tp = &dhu_tty[unit]; 181*20976Smckusick if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 182*20976Smckusick return (EBUSY); 183*20976Smckusick addr = (struct dhudevice *)ui->ui_addr; 184*20976Smckusick tp->t_addr = (caddr_t)addr; 185*20976Smckusick tp->t_oproc = dhustart; 186*20976Smckusick /* 187*20976Smckusick * While setting up state for this uba and this dhu, 188*20976Smckusick * block uba resets which can clear the state. 189*20976Smckusick */ 190*20976Smckusick s = spl5(); 191*20976Smckusick if (dhu_ubinfo[ui->ui_ubanum] == 0) { 192*20976Smckusick dhu_ubinfo[ui->ui_ubanum] = 193*20976Smckusick uballoc(ui->ui_ubanum, (caddr_t)cfree, 194*20976Smckusick nclist*sizeof(struct cblock), 0); 195*20976Smckusick cbase[ui->ui_ubanum] = dhu_ubinfo[ui->ui_ubanum]&0x3ffff; 196*20976Smckusick } 197*20976Smckusick if ((dhuact&(1<<dhu)) == 0) { 198*20976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 199*20976Smckusick addr->dhutimo = DHU_DEF_TIMO; 200*20976Smckusick dhuact |= (1<<dhu); 201*20976Smckusick /* anything else to configure whole board */ 202*20976Smckusick } 203*20976Smckusick (void) splx(s); 204*20976Smckusick /* 205*20976Smckusick * If this is first open, initialize tty state to default. 206*20976Smckusick */ 207*20976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 208*20976Smckusick ttychars(tp); 209*20976Smckusick #ifndef PORTSELECTOR 210*20976Smckusick if (tp->t_ispeed == 0) { 211*20976Smckusick #else 212*20976Smckusick tp->t_state |= TS_HUPCLS; 213*20976Smckusick #endif PORTSELECTOR 214*20976Smckusick tp->t_ispeed = ISPEED; 215*20976Smckusick tp->t_ospeed = ISPEED; 216*20976Smckusick tp->t_flags = IFLAGS; 217*20976Smckusick #ifndef PORTSELECTOR 218*20976Smckusick } 219*20976Smckusick #endif PORTSELECTOR 220*20976Smckusick tp->t_dev = dev; 221*20976Smckusick dhuparam(unit); 222*20976Smckusick } 223*20976Smckusick /* 224*20976Smckusick * Wait for carrier, then process line discipline specific open. 225*20976Smckusick */ 226*20976Smckusick s = spl5(); 227*20976Smckusick if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 228*20976Smckusick (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 229*20976Smckusick tp->t_state |= TS_CARR_ON; 230*20976Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 231*20976Smckusick tp->t_state |= TS_WOPEN; 232*20976Smckusick sleep((caddr_t)&tp->t_rawq, TTIPRI); 233*20976Smckusick } 234*20976Smckusick (void) splx(s); 235*20976Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp)); 236*20976Smckusick } 237*20976Smckusick 238*20976Smckusick /* 239*20976Smckusick * Close a DHU11 line, turning off the modem control. 240*20976Smckusick */ 241*20976Smckusick /*ARGSUSED*/ 242*20976Smckusick dhuclose(dev, flag) 243*20976Smckusick dev_t dev; 244*20976Smckusick int flag; 245*20976Smckusick { 246*20976Smckusick register struct tty *tp; 247*20976Smckusick register unit; 248*20976Smckusick 249*20976Smckusick unit = UNIT(dev); 250*20976Smckusick tp = &dhu_tty[unit]; 251*20976Smckusick (*linesw[tp->t_line].l_close)(tp); 252*20976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 253*20976Smckusick if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0) 254*20976Smckusick #ifdef PORTSELECTOR 255*20976Smckusick { 256*20976Smckusick extern int wakeup(); 257*20976Smckusick 258*20976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 259*20976Smckusick /* Hold DTR low for 0.5 seconds */ 260*20976Smckusick timeout(wakeup, (caddr_t) &tp->t_dev, hz/2); 261*20976Smckusick sleep((caddr_t) &tp->t_dev, PZERO); 262*20976Smckusick } 263*20976Smckusick #else 264*20976Smckusick (void) dhumctl(unit, DHU_OFF, DMSET); 265*20976Smckusick #endif PORTSELECTOR 266*20976Smckusick ttyclose(tp); 267*20976Smckusick } 268*20976Smckusick 269*20976Smckusick dhuread(dev, uio) 270*20976Smckusick dev_t dev; 271*20976Smckusick struct uio *uio; 272*20976Smckusick { 273*20976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 274*20976Smckusick 275*20976Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio)); 276*20976Smckusick } 277*20976Smckusick 278*20976Smckusick dhuwrite(dev, uio) 279*20976Smckusick dev_t dev; 280*20976Smckusick struct uio *uio; 281*20976Smckusick { 282*20976Smckusick register struct tty *tp = &dhu_tty[UNIT(dev)]; 283*20976Smckusick 284*20976Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio)); 285*20976Smckusick } 286*20976Smckusick 287*20976Smckusick /* 288*20976Smckusick * DHU11 receiver interrupt. 289*20976Smckusick */ 290*20976Smckusick dhurint(dhu) 291*20976Smckusick int dhu; 292*20976Smckusick { 293*20976Smckusick register struct tty *tp; 294*20976Smckusick register c; 295*20976Smckusick register struct dhudevice *addr; 296*20976Smckusick register struct tty *tp0; 297*20976Smckusick register struct uba_device *ui; 298*20976Smckusick register line; 299*20976Smckusick int overrun = 0; 300*20976Smckusick 301*20976Smckusick ui = dhuinfo[dhu]; 302*20976Smckusick if (ui == 0 || ui->ui_alive == 0) 303*20976Smckusick return; 304*20976Smckusick addr = (struct dhudevice *)ui->ui_addr; 305*20976Smckusick tp0 = &dhu_tty[dhu<<4]; 306*20976Smckusick /* 307*20976Smckusick * Loop fetching characters from the silo for this 308*20976Smckusick * dhu until there are no more in the silo. 309*20976Smckusick */ 310*20976Smckusick while ((c = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 311*20976Smckusick line = DHU_RX_LINE(c); 312*20976Smckusick tp = tp0 + line; 313*20976Smckusick if ((c & DHU_RB_STAT) == DHU_RB_STAT) { 314*20976Smckusick /* 315*20976Smckusick * modem changed or diag info 316*20976Smckusick */ 317*20976Smckusick if (c & DHU_RB_DIAG) { 318*20976Smckusick /* decode diagnostic messages */ 319*20976Smckusick continue; 320*20976Smckusick } 321*20976Smckusick if ((tp->t_state & TS_WOPEN) == 0 && 322*20976Smckusick (tp->t_flags & MDMBUF)) { 323*20976Smckusick if (c & DHU_ST_DCD) { 324*20976Smckusick tp->t_state &= ~TS_TTSTOP; 325*20976Smckusick ttstart(tp); 326*20976Smckusick } else if ((tp->t_state & TS_TTSTOP) == 0) { 327*20976Smckusick tp->t_state |= TS_TTSTOP; 328*20976Smckusick dhustop(tp, 0); 329*20976Smckusick } 330*20976Smckusick } else if ((c & DHU_ST_DCD) == 0 && 331*20976Smckusick (dhusoftCAR[dhu] & (1<<line)) == 0) { 332*20976Smckusick if ((tp->t_state & TS_WOPEN) == 0 && 333*20976Smckusick (tp->t_flags & NOHANG) == 0) { 334*20976Smckusick gsignal(tp->t_pgrp, SIGHUP); 335*20976Smckusick gsignal(tp->t_pgrp, SIGCONT); 336*20976Smckusick (void) dhumctl((dhu<<4)|line, 337*20976Smckusick DHU_OFF, DMSET); 338*20976Smckusick ttyflush(tp, FREAD|FWRITE); 339*20976Smckusick } 340*20976Smckusick tp->t_state &= ~TS_CARR_ON; 341*20976Smckusick } else { 342*20976Smckusick if ((tp->t_state & TS_CARR_ON) == 0) { 343*20976Smckusick tp->t_state |= TS_CARR_ON; 344*20976Smckusick wakeup((caddr_t)&tp->t_rawq); 345*20976Smckusick } 346*20976Smckusick } 347*20976Smckusick continue; 348*20976Smckusick } 349*20976Smckusick if ((tp->t_state&TS_ISOPEN) == 0) { 350*20976Smckusick wakeup((caddr_t)&tp->t_rawq); 351*20976Smckusick #ifdef PORTSELECTOR 352*20976Smckusick if ((tp->t_state&TS_WOPEN) == 0) 353*20976Smckusick #endif 354*20976Smckusick continue; 355*20976Smckusick } 356*20976Smckusick if (c & DHU_RB_PE) 357*20976Smckusick if ((tp->t_flags&(EVENP|ODDP)) == EVENP || 358*20976Smckusick (tp->t_flags&(EVENP|ODDP)) == ODDP) 359*20976Smckusick continue; 360*20976Smckusick if ((c & DHU_RB_DO) && overrun == 0) { 361*20976Smckusick log(KERN_RECOV, "dhu%d: silo overflow\n", dhu); 362*20976Smckusick overrun = 1; 363*20976Smckusick } 364*20976Smckusick if (c & DHU_RB_FE) 365*20976Smckusick /* 366*20976Smckusick * At framing error (break) generate 367*20976Smckusick * a null (in raw mode, for getty), or a 368*20976Smckusick * interrupt (in cooked/cbreak mode). 369*20976Smckusick */ 370*20976Smckusick if (tp->t_flags&RAW) 371*20976Smckusick c = 0; 372*20976Smckusick else 373*20976Smckusick c = tp->t_intrc; 374*20976Smckusick #if NBK > 0 375*20976Smckusick if (tp->t_line == NETLDISC) { 376*20976Smckusick c &= 0x7f; 377*20976Smckusick BKINPUT(c, tp); 378*20976Smckusick } else 379*20976Smckusick #endif 380*20976Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 381*20976Smckusick } 382*20976Smckusick } 383*20976Smckusick 384*20976Smckusick /* 385*20976Smckusick * Ioctl for DHU11. 386*20976Smckusick */ 387*20976Smckusick /*ARGSUSED*/ 388*20976Smckusick dhuioctl(dev, cmd, data, flag) 389*20976Smckusick caddr_t data; 390*20976Smckusick { 391*20976Smckusick register struct tty *tp; 392*20976Smckusick register int unit = UNIT(dev); 393*20976Smckusick register dhu = unit>>4; 394*20976Smckusick register bit = (1<<(unit&0xf)); 395*20976Smckusick int error; 396*20976Smckusick 397*20976Smckusick tp = &dhu_tty[unit]; 398*20976Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 399*20976Smckusick if (error >= 0) 400*20976Smckusick return (error); 401*20976Smckusick error = ttioctl(tp, cmd, data, flag); 402*20976Smckusick if (error >= 0) { 403*20976Smckusick if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET || 404*20976Smckusick cmd == TIOCLBIC || cmd == TIOCLBIS) 405*20976Smckusick dhuparam(unit); 406*20976Smckusick return (error); 407*20976Smckusick } 408*20976Smckusick 409*20976Smckusick switch (cmd) { 410*20976Smckusick case TIOCSBRK: 411*20976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIS); 412*20976Smckusick break; 413*20976Smckusick 414*20976Smckusick case TIOCCBRK: 415*20976Smckusick (void) dhumctl(unit, DHU_BRK, DMBIC); 416*20976Smckusick break; 417*20976Smckusick 418*20976Smckusick case TIOCSDTR: 419*20976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 420*20976Smckusick break; 421*20976Smckusick 422*20976Smckusick case TIOCCDTR: 423*20976Smckusick (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 424*20976Smckusick break; 425*20976Smckusick 426*20976Smckusick case TIOCMSET: 427*20976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 428*20976Smckusick break; 429*20976Smckusick 430*20976Smckusick case TIOCMBIS: 431*20976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 432*20976Smckusick break; 433*20976Smckusick 434*20976Smckusick case TIOCMBIC: 435*20976Smckusick (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 436*20976Smckusick break; 437*20976Smckusick 438*20976Smckusick case TIOCMGET: 439*20976Smckusick *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 440*20976Smckusick break; 441*20976Smckusick default: 442*20976Smckusick return (ENOTTY); 443*20976Smckusick } 444*20976Smckusick return (0); 445*20976Smckusick } 446*20976Smckusick 447*20976Smckusick dmtodhu(bits) 448*20976Smckusick register int bits; 449*20976Smckusick { 450*20976Smckusick register int b = 0; 451*20976Smckusick 452*20976Smckusick if (bits & DML_RTS) b |= DHU_RTS; 453*20976Smckusick if (bits & DML_DTR) b |= DHU_DTR; 454*20976Smckusick if (bits & DML_LE) b |= DHU_LE; 455*20976Smckusick return(b); 456*20976Smckusick } 457*20976Smckusick 458*20976Smckusick dhutodm(bits) 459*20976Smckusick register int bits; 460*20976Smckusick { 461*20976Smckusick register int b = 0; 462*20976Smckusick 463*20976Smckusick if (bits & DHU_DSR) b |= DML_DSR; 464*20976Smckusick if (bits & DHU_RNG) b |= DML_RNG; 465*20976Smckusick if (bits & DHU_CAR) b |= DML_CAR; 466*20976Smckusick if (bits & DHU_CTS) b |= DML_CTS; 467*20976Smckusick if (bits & DHU_RTS) b |= DML_RTS; 468*20976Smckusick if (bits & DHU_DTR) b |= DML_DTR; 469*20976Smckusick if (bits & DHU_LE) b |= DML_LE; 470*20976Smckusick return(b); 471*20976Smckusick } 472*20976Smckusick 473*20976Smckusick 474*20976Smckusick /* 475*20976Smckusick * Set parameters from open or stty into the DHU hardware 476*20976Smckusick * registers. 477*20976Smckusick */ 478*20976Smckusick dhuparam(unit) 479*20976Smckusick register int unit; 480*20976Smckusick { 481*20976Smckusick register struct tty *tp; 482*20976Smckusick register struct dhudevice *addr; 483*20976Smckusick register int lpar; 484*20976Smckusick int s; 485*20976Smckusick 486*20976Smckusick tp = &dhu_tty[unit]; 487*20976Smckusick addr = (struct dhudevice *)tp->t_addr; 488*20976Smckusick /* 489*20976Smckusick * Block interrupts so parameters will be set 490*20976Smckusick * before the line interrupts. 491*20976Smckusick */ 492*20976Smckusick s = spl5(); 493*20976Smckusick if ((tp->t_ispeed) == 0) { 494*20976Smckusick tp->t_state |= TS_HUPCLS; 495*20976Smckusick (void)dhumctl(unit, DHU_OFF, DMSET); 496*20976Smckusick splx(s); 497*20976Smckusick return; 498*20976Smckusick } 499*20976Smckusick lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8); 500*20976Smckusick if ((tp->t_ispeed) == B134) 501*20976Smckusick lpar |= DHU_LP_BITS6|DHU_LP_PENABLE; 502*20976Smckusick else if (tp->t_flags & (RAW|LITOUT)) 503*20976Smckusick lpar |= DHU_LP_BITS8; 504*20976Smckusick else 505*20976Smckusick lpar |= DHU_LP_BITS7|DHU_LP_PENABLE; 506*20976Smckusick if (tp->t_flags&EVENP) 507*20976Smckusick lpar |= DHU_LP_EPAR; 508*20976Smckusick if ((tp->t_ospeed) == B110) 509*20976Smckusick lpar |= DHU_LP_TWOSB; 510*20976Smckusick addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 511*20976Smckusick addr->dhulpr = lpar; 512*20976Smckusick splx(s); 513*20976Smckusick } 514*20976Smckusick 515*20976Smckusick /* 516*20976Smckusick * DHU11 transmitter interrupt. 517*20976Smckusick * Restart each line which used to be active but has 518*20976Smckusick * terminated transmission since the last interrupt. 519*20976Smckusick */ 520*20976Smckusick dhuxint(dhu) 521*20976Smckusick int dhu; 522*20976Smckusick { 523*20976Smckusick register struct tty *tp; 524*20976Smckusick register struct dhudevice *addr; 525*20976Smckusick register struct tty *tp0; 526*20976Smckusick register struct uba_device *ui; 527*20976Smckusick register int line, t; 528*20976Smckusick u_short cntr; 529*20976Smckusick 530*20976Smckusick ui = dhuinfo[dhu]; 531*20976Smckusick tp0 = &dhu_tty[dhu<<4]; 532*20976Smckusick addr = (struct dhudevice *)ui->ui_addr; 533*20976Smckusick while ((t = addr->dhucsrh) & DHU_CSH_TI) { 534*20976Smckusick line = DHU_TX_LINE(t); 535*20976Smckusick tp = tp0 + line; 536*20976Smckusick tp->t_state &= ~TS_BUSY; 537*20976Smckusick if (t & DHU_CSH_NXM) { 538*20976Smckusick printf("dhu(%d,%d): NXM fault\n", dhu, line); 539*20976Smckusick /* SHOULD RESTART OR SOMETHING... */ 540*20976Smckusick } 541*20976Smckusick if (tp->t_state&TS_FLUSH) 542*20976Smckusick tp->t_state &= ~TS_FLUSH; 543*20976Smckusick else { 544*20976Smckusick addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 545*20976Smckusick /* 546*20976Smckusick * Do arithmetic in a short to make up 547*20976Smckusick * for lost 16&17 bits. 548*20976Smckusick */ 549*20976Smckusick cntr = addr->dhubar1 - 550*20976Smckusick UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 551*20976Smckusick ndflush(&tp->t_outq, (int)cntr); 552*20976Smckusick } 553*20976Smckusick if (tp->t_line) 554*20976Smckusick (*linesw[tp->t_line].l_start)(tp); 555*20976Smckusick else 556*20976Smckusick dhustart(tp); 557*20976Smckusick } 558*20976Smckusick } 559*20976Smckusick 560*20976Smckusick /* 561*20976Smckusick * Start (restart) transmission on the given DHU11 line. 562*20976Smckusick */ 563*20976Smckusick dhustart(tp) 564*20976Smckusick register struct tty *tp; 565*20976Smckusick { 566*20976Smckusick register struct dhudevice *addr; 567*20976Smckusick register int car, dhu, unit, nch; 568*20976Smckusick int s; 569*20976Smckusick 570*20976Smckusick unit = minor(tp->t_dev); 571*20976Smckusick dhu = unit >> 4; 572*20976Smckusick unit &= 0xf; 573*20976Smckusick addr = (struct dhudevice *)tp->t_addr; 574*20976Smckusick 575*20976Smckusick /* 576*20976Smckusick * Must hold interrupts in following code to prevent 577*20976Smckusick * state of the tp from changing. 578*20976Smckusick */ 579*20976Smckusick s = spl5(); 580*20976Smckusick /* 581*20976Smckusick * If it's currently active, or delaying, no need to do anything. 582*20976Smckusick */ 583*20976Smckusick if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 584*20976Smckusick goto out; 585*20976Smckusick /* 586*20976Smckusick * If there are sleepers, and output has drained below low 587*20976Smckusick * water mark, wake up the sleepers.. 588*20976Smckusick */ 589*20976Smckusick if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 590*20976Smckusick if (tp->t_state&TS_ASLEEP) { 591*20976Smckusick tp->t_state &= ~TS_ASLEEP; 592*20976Smckusick wakeup((caddr_t)&tp->t_outq); 593*20976Smckusick } 594*20976Smckusick if (tp->t_wsel) { 595*20976Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 596*20976Smckusick tp->t_wsel = 0; 597*20976Smckusick tp->t_state &= ~TS_WCOLL; 598*20976Smckusick } 599*20976Smckusick } 600*20976Smckusick /* 601*20976Smckusick * Now restart transmission unless the output queue is 602*20976Smckusick * empty. 603*20976Smckusick */ 604*20976Smckusick if (tp->t_outq.c_cc == 0) 605*20976Smckusick goto out; 606*20976Smckusick if (tp->t_flags & (RAW|LITOUT)) 607*20976Smckusick nch = ndqb(&tp->t_outq, 0); 608*20976Smckusick else { 609*20976Smckusick nch = ndqb(&tp->t_outq, 0200); 610*20976Smckusick /* 611*20976Smckusick * If first thing on queue is a delay process it. 612*20976Smckusick */ 613*20976Smckusick if (nch == 0) { 614*20976Smckusick nch = getc(&tp->t_outq); 615*20976Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 616*20976Smckusick tp->t_state |= TS_TIMEOUT; 617*20976Smckusick goto out; 618*20976Smckusick } 619*20976Smckusick } 620*20976Smckusick /* 621*20976Smckusick * If characters to transmit, restart transmission. 622*20976Smckusick */ 623*20976Smckusick if (nch) { 624*20976Smckusick car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 625*20976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 626*20976Smckusick addr->dhulcr &= ~DHU_LC_TXABORT; 627*20976Smckusick addr->dhubcr = nch; 628*20976Smckusick addr->dhubar1 = car; 629*20976Smckusick addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 630*20976Smckusick DHU_BA2_DMAGO; 631*20976Smckusick tp->t_state |= TS_BUSY; 632*20976Smckusick } 633*20976Smckusick out: 634*20976Smckusick splx(s); 635*20976Smckusick } 636*20976Smckusick 637*20976Smckusick /* 638*20976Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush. 639*20976Smckusick */ 640*20976Smckusick /*ARGSUSED*/ 641*20976Smckusick dhustop(tp, flag) 642*20976Smckusick register struct tty *tp; 643*20976Smckusick { 644*20976Smckusick register struct dhudevice *addr; 645*20976Smckusick register int unit, s; 646*20976Smckusick 647*20976Smckusick addr = (struct dhudevice *)tp->t_addr; 648*20976Smckusick /* 649*20976Smckusick * Block input/output interrupts while messing with state. 650*20976Smckusick */ 651*20976Smckusick s = spl5(); 652*20976Smckusick if (tp->t_state & TS_BUSY) { 653*20976Smckusick /* 654*20976Smckusick * Device is transmitting; stop output 655*20976Smckusick * by selecting the line and setting the 656*20976Smckusick * abort xmit bit. We will get an xmit interrupt, 657*20976Smckusick * where we will figure out where to continue the 658*20976Smckusick * next time the transmitter is enabled. If 659*20976Smckusick * TS_FLUSH is set, the outq will be flushed. 660*20976Smckusick * In either case, dhustart will clear the TXABORT bit. 661*20976Smckusick */ 662*20976Smckusick unit = minor(tp->t_dev); 663*20976Smckusick addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 664*20976Smckusick addr->dhulcr |= DHU_LC_TXABORT; 665*20976Smckusick if ((tp->t_state&TS_TTSTOP)==0) 666*20976Smckusick tp->t_state |= TS_FLUSH; 667*20976Smckusick } 668*20976Smckusick (void) splx(s); 669*20976Smckusick } 670*20976Smckusick 671*20976Smckusick /* 672*20976Smckusick * DHU11 modem control 673*20976Smckusick */ 674*20976Smckusick dhumctl(dev, bits, how) 675*20976Smckusick dev_t dev; 676*20976Smckusick int bits, how; 677*20976Smckusick { 678*20976Smckusick register struct dhudevice *dhuaddr; 679*20976Smckusick register int unit, mbits, lcr; 680*20976Smckusick int s; 681*20976Smckusick 682*20976Smckusick unit = UNIT(dev); 683*20976Smckusick dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 684*20976Smckusick unit &= 0xf; 685*20976Smckusick s = spl5(); 686*20976Smckusick dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 687*20976Smckusick /* 688*20976Smckusick * combine byte from stat register (read only, bits 16..23) 689*20976Smckusick * with lcr register (read write, bits 0..15). 690*20976Smckusick */ 691*20976Smckusick mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 692*20976Smckusick switch (how) { 693*20976Smckusick case DMSET: 694*20976Smckusick mbits = (mbits & 0xff0000) | bits; 695*20976Smckusick break; 696*20976Smckusick 697*20976Smckusick case DMBIS: 698*20976Smckusick mbits |= bits; 699*20976Smckusick break; 700*20976Smckusick 701*20976Smckusick case DMBIC: 702*20976Smckusick mbits &= ~bits; 703*20976Smckusick break; 704*20976Smckusick 705*20976Smckusick case DMGET: 706*20976Smckusick (void) splx(s); 707*20976Smckusick return(mbits); 708*20976Smckusick } 709*20976Smckusick dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 710*20976Smckusick dhuaddr->dhulcr2 = DHU_LC2_TXEN; 711*20976Smckusick (void) splx(s); 712*20976Smckusick return(mbits); 713*20976Smckusick } 714*20976Smckusick 715*20976Smckusick /* 716*20976Smckusick * Reset state of driver if UBA reset was necessary. 717*20976Smckusick * Reset the line and modem control registers. 718*20976Smckusick * restart transmitters. 719*20976Smckusick */ 720*20976Smckusick dhureset(uban) 721*20976Smckusick int uban; 722*20976Smckusick { 723*20976Smckusick register int dhu, unit; 724*20976Smckusick register struct tty *tp; 725*20976Smckusick register struct uba_device *ui; 726*20976Smckusick register struct dhudevice *addr; 727*20976Smckusick int i; 728*20976Smckusick register int s; 729*20976Smckusick 730*20976Smckusick if (dhu_ubinfo[uban] == 0) 731*20976Smckusick return; 732*20976Smckusick dhu_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 733*20976Smckusick nclist*sizeof (struct cblock), 0); 734*20976Smckusick cbase[uban] = dhu_ubinfo[uban]&0x3ffff; 735*20976Smckusick for (dhu = 0; dhu < NDHU; dhu++) { 736*20976Smckusick ui = dhuinfo[dhu]; 737*20976Smckusick if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 738*20976Smckusick continue; 739*20976Smckusick printf(" dhu%d", dhu); 740*20976Smckusick addr = (struct dhudevice *)ui->ui_addr; 741*20976Smckusick addr->dhucsr = DHU_SELECT(0) | DHU_IE; 742*20976Smckusick addr->dhutimo = DHU_DEF_TIMO; 743*20976Smckusick unit = dhu * 16; 744*20976Smckusick for (i = 0; i < 16; i++) { 745*20976Smckusick tp = &dhu_tty[unit]; 746*20976Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 747*20976Smckusick dhuparam(unit); 748*20976Smckusick (void)dhumctl(unit, DHU_ON, DMSET); 749*20976Smckusick tp->t_state &= ~TS_BUSY; 750*20976Smckusick dhustart(tp); 751*20976Smckusick } 752*20976Smckusick unit++; 753*20976Smckusick } 754*20976Smckusick } 755*20976Smckusick } 756*20976Smckusick #endif 757