1*13Sbill /* dh.c 3.1 10/14/12 */ 2*13Sbill 3*13Sbill /* 4*13Sbill * DH-11 driver 5*13Sbill * This driver calls on the DHDM driver. 6*13Sbill * If the DH has no DM11-BB, then the latter will 7*13Sbill * be fake. To insure loading of the correct DM code, 8*13Sbill * lib2 should have dhdm.o, dh.o and dhfdm.o in that order. 9*13Sbill */ 10*13Sbill 11*13Sbill #include "../h/param.h" 12*13Sbill #include "../h/conf.h" 13*13Sbill #include "../h/dir.h" 14*13Sbill #include "../h/user.h" 15*13Sbill #include "../h/tty.h" 16*13Sbill #include "../h/map.h" 17*13Sbill #include "../h/pte.h" 18*13Sbill #include "../h/uba.h" 19*13Sbill 20*13Sbill #define q3 tp->t_outq 21*13Sbill #define DHADDR ((struct device *)(UBA0_DEV + 0160020)) 22*13Sbill #define NDH11 16 /* number of lines */ 23*13Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree)) 24*13Sbill 25*13Sbill struct cblock { 26*13Sbill struct cblock *c_next; 27*13Sbill char c_info[CBSIZE]; 28*13Sbill }; 29*13Sbill 30*13Sbill struct tty dh11[NDH11]; 31*13Sbill short dhcc[NDH11]; 32*13Sbill int dhchars[(NDH11+15)/16]; 33*13Sbill int ndh11 = NDH11; 34*13Sbill int dhstart(); 35*13Sbill int ttrstrt(); 36*13Sbill int cbase; 37*13Sbill extern struct cblock cfree[]; 38*13Sbill 39*13Sbill /* 40*13Sbill * Hardware control bits 41*13Sbill */ 42*13Sbill #define BITS6 01 43*13Sbill #define BITS7 02 44*13Sbill #define BITS8 03 45*13Sbill #define TWOSB 04 46*13Sbill #define PENABLE 020 47*13Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 48*13Sbill #define OPAR 040 49*13Sbill #define HDUPLX 040000 50*13Sbill 51*13Sbill #define IENAB 030100 52*13Sbill #define PERROR 010000 53*13Sbill #define FRERROR 020000 54*13Sbill #define OVERRUN 040000 55*13Sbill #define XINT 0100000 56*13Sbill #define SSPEED 7 /* standard speed: 300 baud */ 57*13Sbill 58*13Sbill #ifdef ERNIE 59*13Sbill #define DHTIME 2 /* Since Berknet packets are only 100 chars */ 60*13Sbill #else 61*13Sbill #define DHTIME 6 62*13Sbill #endif 63*13Sbill extern int dhtimer(); 64*13Sbill 65*13Sbill /* 66*13Sbill * DM control bits 67*13Sbill */ 68*13Sbill #define TURNON 03 /* CD lead + line enable */ 69*13Sbill #define TURNOFF 01 /* line enable */ 70*13Sbill #define RQS 04 /* request to send */ 71*13Sbill 72*13Sbill /* 73*13Sbill * Software copy of last dhbar 74*13Sbill */ 75*13Sbill short dhsar[(NDH11+15)/16]; 76*13Sbill 77*13Sbill struct device 78*13Sbill { 79*13Sbill union { 80*13Sbill short dhcsr; 81*13Sbill char dhcsrl; 82*13Sbill } un; 83*13Sbill short dhnxch; 84*13Sbill short dhlpr; 85*13Sbill unsigned short dhcar; 86*13Sbill short dhbcr; 87*13Sbill unsigned short dhbar; 88*13Sbill short dhbreak; 89*13Sbill short dhsilo; 90*13Sbill }; 91*13Sbill 92*13Sbill /* 93*13Sbill * Open a DH11 line. 94*13Sbill */ 95*13Sbill /*ARGSUSED*/ 96*13Sbill dhopen(dev, flag) 97*13Sbill { 98*13Sbill register struct tty *tp; 99*13Sbill register d; 100*13Sbill register struct device *addr; 101*13Sbill static timer_on; 102*13Sbill int s; 103*13Sbill 104*13Sbill d = minor(dev) & 0177; 105*13Sbill if (d >= NDH11) { 106*13Sbill u.u_error = ENXIO; 107*13Sbill return; 108*13Sbill } 109*13Sbill tp = &dh11[d]; 110*13Sbill addr = DHADDR; 111*13Sbill addr += d>>4; 112*13Sbill tp->t_addr = (caddr_t)addr; 113*13Sbill tp->t_oproc = dhstart; 114*13Sbill tp->t_iproc = NULL; 115*13Sbill tp->t_state |= WOPEN; 116*13Sbill s = spl6(); 117*13Sbill if (!timer_on) { 118*13Sbill timer_on++; 119*13Sbill timeout(dhtimer, (caddr_t)0, DHTIME); 120*13Sbill cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0); 121*13Sbill } 122*13Sbill splx(s); 123*13Sbill addr->un.dhcsr |= IENAB; 124*13Sbill if ((tp->t_state&ISOPEN) == 0) { 125*13Sbill ttychars(tp); 126*13Sbill tp->t_ispeed = SSPEED; 127*13Sbill tp->t_ospeed = SSPEED; 128*13Sbill tp->t_flags = ODDP|EVENP|ECHO; 129*13Sbill dhparam(d); 130*13Sbill } 131*13Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 132*13Sbill u.u_error = EBUSY; 133*13Sbill return; 134*13Sbill } 135*13Sbill dmopen(dev); 136*13Sbill (*linesw[tp->t_line].l_open)(dev,tp); 137*13Sbill } 138*13Sbill 139*13Sbill /* 140*13Sbill * Close a DH11 line. 141*13Sbill */ 142*13Sbill /*ARGSUSED*/ 143*13Sbill dhclose(dev, flag) 144*13Sbill dev_t dev; 145*13Sbill int flag; 146*13Sbill { 147*13Sbill register struct tty *tp; 148*13Sbill register d; 149*13Sbill 150*13Sbill d = minor(dev) & 0177; 151*13Sbill tp = &dh11[d]; 152*13Sbill (*linesw[tp->t_line].l_close)(tp); 153*13Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 154*13Sbill dmctl(d, TURNOFF); 155*13Sbill ttyclose(tp); 156*13Sbill } 157*13Sbill 158*13Sbill /* 159*13Sbill * Read from a DH11 line. 160*13Sbill */ 161*13Sbill dhread(dev) 162*13Sbill { 163*13Sbill register struct tty *tp; 164*13Sbill 165*13Sbill tp = &dh11[minor(dev) & 0177]; 166*13Sbill (*linesw[tp->t_line].l_read)(tp); 167*13Sbill } 168*13Sbill 169*13Sbill /* 170*13Sbill * write on a DH11 line 171*13Sbill */ 172*13Sbill dhwrite(dev) 173*13Sbill { 174*13Sbill register struct tty *tp; 175*13Sbill 176*13Sbill tp = &dh11[minor(dev) & 0177]; 177*13Sbill (*linesw[tp->t_line].l_write)(tp); 178*13Sbill } 179*13Sbill 180*13Sbill /* 181*13Sbill * DH11 receiver interrupt. 182*13Sbill */ 183*13Sbill dhrint(dev) 184*13Sbill { 185*13Sbill register struct tty *tp; 186*13Sbill register short c; 187*13Sbill register struct device *addr; 188*13Sbill 189*13Sbill addr = DHADDR; 190*13Sbill addr += minor(dev) & 0177; 191*13Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 192*13Sbill tp = &dh11[((minor(dev)&0177)<<4) + ((c>>8)&017)]; 193*13Sbill dhchars[minor(dev)&0177]++; 194*13Sbill if (tp >= &dh11[NDH11]) 195*13Sbill continue; 196*13Sbill if((tp->t_state&ISOPEN)==0) { 197*13Sbill wakeup((caddr_t)tp); 198*13Sbill continue; 199*13Sbill } 200*13Sbill if (c&PERROR) 201*13Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 202*13Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 203*13Sbill continue; 204*13Sbill if (c&OVERRUN) 205*13Sbill printf("O"); 206*13Sbill if (c&FRERROR) /* break */ 207*13Sbill if (tp->t_flags&RAW) 208*13Sbill c = 0; /* null (for getty) */ 209*13Sbill else 210*13Sbill c = 0177; /* DEL (intr) */ 211*13Sbill (*linesw[tp->t_line].l_rint)(c,tp); 212*13Sbill } 213*13Sbill } 214*13Sbill 215*13Sbill /* 216*13Sbill * stty/gtty for DH11 217*13Sbill */ 218*13Sbill /*ARGSUSED*/ 219*13Sbill dhioctl(dev, cmd, addr, flag) 220*13Sbill caddr_t addr; 221*13Sbill { 222*13Sbill register struct tty *tp; 223*13Sbill 224*13Sbill tp = &dh11[minor(dev) & 0177]; 225*13Sbill if (ttioccomm(cmd, tp, addr, dev)) { 226*13Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 227*13Sbill dhparam(dev); 228*13Sbill } else if (cmd==TIOCSBRK) { 229*13Sbill /* send a break */ 230*13Sbill register int linebit = 1 << (dev&017); 231*13Sbill extern dhunbrk(); 232*13Sbill 233*13Sbill wflushtty(tp); 234*13Sbill spl5(); 235*13Sbill ((struct device *)tp->t_addr)->dhbreak |= linebit; 236*13Sbill tp->t_state |= TIMEOUT; 237*13Sbill timeout(dhunbrk, (caddr_t)tp, 25); /* 300-500 ms */ 238*13Sbill while (((struct device *)tp->t_addr)->dhbreak & linebit) 239*13Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 240*13Sbill tp->t_state &= ~TIMEOUT; 241*13Sbill spl0(); 242*13Sbill flushtty(tp); 243*13Sbill return; 244*13Sbill } else 245*13Sbill u.u_error = ENOTTY; 246*13Sbill } 247*13Sbill 248*13Sbill dhunbrk(tp) 249*13Sbill register struct tty *tp; 250*13Sbill { 251*13Sbill 252*13Sbill ((struct device *)tp->t_addr)->dhbreak &= ~ (1 << (minor(tp->t_dev)&017)); 253*13Sbill wakeup((caddr_t)&tp->t_rawq); 254*13Sbill } 255*13Sbill 256*13Sbill /* 257*13Sbill * Set parameters from open or stty into the DH hardware 258*13Sbill * registers. 259*13Sbill */ 260*13Sbill dhparam(dev) 261*13Sbill { 262*13Sbill register struct tty *tp; 263*13Sbill register struct device *addr; 264*13Sbill register d; 265*13Sbill 266*13Sbill d = minor(dev) & 0177; 267*13Sbill tp = &dh11[d]; 268*13Sbill addr = (struct device *)tp->t_addr; 269*13Sbill spl5(); 270*13Sbill addr->un.dhcsrl = (d&017) | IENAB; 271*13Sbill /* 272*13Sbill * Hang up line? 273*13Sbill */ 274*13Sbill if ((tp->t_ispeed)==0) { 275*13Sbill tp->t_state |= HUPCLS; 276*13Sbill dmctl(d, TURNOFF); 277*13Sbill return; 278*13Sbill } 279*13Sbill d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 280*13Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 281*13Sbill d |= BITS6|PENABLE|HDUPLX; 282*13Sbill else if (tp->t_flags&RAW) 283*13Sbill d |= BITS8; 284*13Sbill else 285*13Sbill d |= BITS7|PENABLE; 286*13Sbill if ((tp->t_flags&EVENP) == 0) 287*13Sbill d |= OPAR; 288*13Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 289*13Sbill d |= TWOSB; 290*13Sbill addr->dhlpr = d; 291*13Sbill spl0(); 292*13Sbill } 293*13Sbill 294*13Sbill /* 295*13Sbill * DH11 transmitter interrupt. 296*13Sbill * Restart each line which used to be active but has 297*13Sbill * terminated transmission since the last interrupt. 298*13Sbill */ 299*13Sbill dhxint(dev) 300*13Sbill { 301*13Sbill register struct tty *tp; 302*13Sbill register struct device *addr; 303*13Sbill register d; 304*13Sbill short ttybit, bar, *sbar; 305*13Sbill 306*13Sbill d = minor(dev) & 0177; 307*13Sbill addr = DHADDR + d; 308*13Sbill addr->un.dhcsr &= (short)~XINT; 309*13Sbill sbar = &dhsar[d]; 310*13Sbill bar = *sbar & ~addr->dhbar; 311*13Sbill d <<= 4; ttybit = 1; 312*13Sbill 313*13Sbill for(; bar; d++, ttybit <<= 1) { 314*13Sbill if(bar&ttybit) { 315*13Sbill *sbar &= ~ttybit; 316*13Sbill bar &= ~ttybit; 317*13Sbill tp = &dh11[d]; 318*13Sbill if (tp->t_line) { 319*13Sbill (*linesw[tp->t_line].l_start)(tp); 320*13Sbill } else { 321*13Sbill addr->un.dhcsrl = (d&017)|IENAB; 322*13Sbill if (tp->t_state&FLUSH) 323*13Sbill tp->t_state &= ~FLUSH; 324*13Sbill else { 325*13Sbill ndflush(&q3, dhcc[d]); 326*13Sbill } 327*13Sbill tp->t_state &= ~BUSY; 328*13Sbill dhstart(tp); 329*13Sbill } 330*13Sbill } 331*13Sbill } 332*13Sbill } 333*13Sbill 334*13Sbill /* 335*13Sbill * Start (restart) transmission on the given DH11 line. 336*13Sbill */ 337*13Sbill dhstart(tp) 338*13Sbill register struct tty *tp; 339*13Sbill { 340*13Sbill register struct device *addr; 341*13Sbill register short nch; 342*13Sbill int s, d; 343*13Sbill 344*13Sbill /* 345*13Sbill * If it's currently active, or delaying, 346*13Sbill * no need to do anything. 347*13Sbill */ 348*13Sbill s = spl5(); 349*13Sbill d = tp-dh11; 350*13Sbill addr = (struct device *)tp->t_addr; 351*13Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 352*13Sbill goto out; 353*13Sbill 354*13Sbill 355*13Sbill /* 356*13Sbill * If the writer was sleeping on output overflow, 357*13Sbill * wake him when low tide is reached. 358*13Sbill */ 359*13Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) { 360*13Sbill tp->t_state &= ~ASLEEP; 361*13Sbill if (tp->t_chan) 362*13Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); else 363*13Sbill wakeup((caddr_t)&tp->t_outq); 364*13Sbill } 365*13Sbill 366*13Sbill if (tp->t_outq.c_cc == 0) 367*13Sbill goto out; 368*13Sbill 369*13Sbill 370*13Sbill 371*13Sbill /* 372*13Sbill * Find number of characters to transfer. 373*13Sbill */ 374*13Sbill if (tp->t_flags & RAW) { 375*13Sbill nch = ndqb(&tp->t_outq, 0); 376*13Sbill } else { 377*13Sbill nch = ndqb(&tp->t_outq, 0200); 378*13Sbill if (nch == 0) { 379*13Sbill nch = getc(&tp->t_outq); 380*13Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 381*13Sbill tp->t_state |= TIMEOUT; 382*13Sbill goto out; 383*13Sbill } 384*13Sbill } 385*13Sbill /* 386*13Sbill * If any characters were set up, start transmission; 387*13Sbill */ 388*13Sbill if (nch) { 389*13Sbill addr->un.dhcsrl = (d&017)|IENAB; 390*13Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 391*13Sbill addr->dhbcr = -nch; 392*13Sbill dhcc[d] = nch; 393*13Sbill nch = 1<<(d&017); 394*13Sbill addr->dhbar |= nch; 395*13Sbill dhsar[d>>4] |= nch; 396*13Sbill tp->t_state |= BUSY; 397*13Sbill } 398*13Sbill out: 399*13Sbill splx(s); 400*13Sbill } 401*13Sbill 402*13Sbill 403*13Sbill /* 404*13Sbill * Stop output on a line. 405*13Sbill * Assume call is made at spl6. 406*13Sbill */ 407*13Sbill /*ARGSUSED*/ 408*13Sbill dhstop(tp, flag) 409*13Sbill register struct tty *tp; 410*13Sbill { 411*13Sbill register s; 412*13Sbill 413*13Sbill s = spl6(); 414*13Sbill if (tp->t_state & BUSY) 415*13Sbill if ((tp->t_state&TTSTOP)==0) 416*13Sbill tp->t_state |= FLUSH; 417*13Sbill splx(s); 418*13Sbill } 419*13Sbill 420*13Sbill /*ARGSUSED*/ 421*13Sbill dhtimer(dev) 422*13Sbill { 423*13Sbill register d,cc; 424*13Sbill register struct device *addr; 425*13Sbill addr = DHADDR; d = 0; 426*13Sbill do { 427*13Sbill cc = dhchars[d]; 428*13Sbill dhchars[d] = 0; 429*13Sbill if (cc > 8*DHTIME) 430*13Sbill cc = 32; else 431*13Sbill if (cc > 3*DHTIME) 432*13Sbill cc = 16; else 433*13Sbill cc = 0; 434*13Sbill addr->dhsilo = cc; 435*13Sbill addr++; 436*13Sbill dhrint(d++); 437*13Sbill } while (d < (NDH11+15)/16); 438*13Sbill timeout(dhtimer, (caddr_t)0, DHTIME); 439*13Sbill } 440