1*300Sbill /* dh.c 3.13 06/23/80 */ 213Sbill 313Sbill /* 413Sbill * DH-11 driver 513Sbill * This driver calls on the DHDM driver. 613Sbill * If the DH has no DM11-BB, then the latter will 713Sbill * be fake. To insure loading of the correct DM code, 813Sbill * lib2 should have dhdm.o, dh.o and dhfdm.o in that order. 913Sbill */ 1013Sbill 1113Sbill #include "../h/param.h" 1213Sbill #include "../h/conf.h" 1313Sbill #include "../h/dir.h" 1413Sbill #include "../h/user.h" 1513Sbill #include "../h/tty.h" 1613Sbill #include "../h/map.h" 1713Sbill #include "../h/pte.h" 1813Sbill #include "../h/uba.h" 19113Sbill #include "../h/bk.h" 2013Sbill 21144Sbill /* 22144Sbill * When running dz's using only SAE (silo alarm) on input 23144Sbill * it is necessary to call dzrint() at clock interrupt time. 24144Sbill * This is unsafe unless spl5()s in tty code are changed to 25144Sbill * spl6()s to block clock interrupts. Note that the dh driver 26144Sbill * currently in use works the same way as the dz, even though 27144Sbill * we could try to more intelligently manage its silo. 28144Sbill * Thus don't take this out if you have no dz's unless you 29144Sbill * change clock.c and dhtimer(). 30144Sbill */ 31144Sbill #define spl5 spl6 32144Sbill 3313Sbill #define DHADDR ((struct device *)(UBA0_DEV + 0160020)) 34280Sbill #define NDH11 32 /* number of lines */ 3513Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree)) 3613Sbill 3713Sbill struct cblock { 3813Sbill struct cblock *c_next; 3913Sbill char c_info[CBSIZE]; 4013Sbill }; 4113Sbill 4213Sbill struct tty dh11[NDH11]; 43117Sbill int dhact; 44280Sbill int dhisilo; 4513Sbill int ndh11 = NDH11; 4613Sbill int dhstart(); 4713Sbill int ttrstrt(); 48280Sbill int dh_ubinfo; 49280Sbill int cbase; 50280Sbill int getcbase; 5113Sbill extern struct cblock cfree[]; 5213Sbill 5313Sbill /* 5413Sbill * Hardware control bits 5513Sbill */ 5613Sbill #define BITS6 01 5713Sbill #define BITS7 02 5813Sbill #define BITS8 03 5913Sbill #define TWOSB 04 6013Sbill #define PENABLE 020 6113Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 6213Sbill #define OPAR 040 6313Sbill #define HDUPLX 040000 6413Sbill 6513Sbill #define IENAB 030100 66105Sbill #define NXM 02000 67105Sbill #define CLRNXM 0400 6813Sbill #define PERROR 010000 6913Sbill #define FRERROR 020000 7013Sbill #define OVERRUN 040000 7113Sbill #define XINT 0100000 7213Sbill #define SSPEED 7 /* standard speed: 300 baud */ 7313Sbill 7413Sbill /* 7513Sbill * DM control bits 7613Sbill */ 7713Sbill #define TURNON 03 /* CD lead + line enable */ 7813Sbill #define TURNOFF 01 /* line enable */ 79168Sbill #define DTR 02 /* data terminal ready */ 8013Sbill #define RQS 04 /* request to send */ 8113Sbill 8213Sbill /* 8313Sbill * Software copy of last dhbar 8413Sbill */ 8513Sbill short dhsar[(NDH11+15)/16]; 8613Sbill 8713Sbill struct device 8813Sbill { 8913Sbill union { 9013Sbill short dhcsr; 9113Sbill char dhcsrl; 9213Sbill } un; 9313Sbill short dhnxch; 9413Sbill short dhlpr; 9513Sbill unsigned short dhcar; 9613Sbill short dhbcr; 9713Sbill unsigned short dhbar; 9813Sbill short dhbreak; 9913Sbill short dhsilo; 10013Sbill }; 10113Sbill 10213Sbill /* 10313Sbill * Open a DH11 line. 10413Sbill */ 10513Sbill /*ARGSUSED*/ 10613Sbill dhopen(dev, flag) 10713Sbill { 10813Sbill register struct tty *tp; 10913Sbill register d; 11013Sbill register struct device *addr; 11113Sbill int s; 11213Sbill 11313Sbill d = minor(dev) & 0177; 11413Sbill if (d >= NDH11) { 11513Sbill u.u_error = ENXIO; 11613Sbill return; 11713Sbill } 11813Sbill tp = &dh11[d]; 11913Sbill addr = DHADDR; 12013Sbill addr += d>>4; 12113Sbill tp->t_addr = (caddr_t)addr; 12213Sbill tp->t_oproc = dhstart; 12313Sbill tp->t_iproc = NULL; 12413Sbill tp->t_state |= WOPEN; 12513Sbill s = spl6(); 126117Sbill if (!getcbase) { 127117Sbill getcbase++; 128280Sbill dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0); 129280Sbill cbase = (short)dh_ubinfo; 13013Sbill } 13113Sbill splx(s); 13213Sbill addr->un.dhcsr |= IENAB; 133117Sbill dhact |= (1<<(d>>4)); 13413Sbill if ((tp->t_state&ISOPEN) == 0) { 13513Sbill ttychars(tp); 136168Sbill if (tp->t_ispeed == 0) { 137168Sbill tp->t_ispeed = SSPEED; 138168Sbill tp->t_ospeed = SSPEED; 139168Sbill tp->t_flags = ODDP|EVENP|ECHO; 140168Sbill } 14113Sbill dhparam(d); 14213Sbill } 14313Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 14413Sbill u.u_error = EBUSY; 14513Sbill return; 14613Sbill } 14713Sbill dmopen(dev); 14813Sbill (*linesw[tp->t_line].l_open)(dev,tp); 14913Sbill } 15013Sbill 15113Sbill /* 15213Sbill * Close a DH11 line. 15313Sbill */ 15413Sbill /*ARGSUSED*/ 15513Sbill dhclose(dev, flag) 15613Sbill dev_t dev; 15713Sbill int flag; 15813Sbill { 15913Sbill register struct tty *tp; 16013Sbill register d; 16113Sbill 16213Sbill d = minor(dev) & 0177; 16313Sbill tp = &dh11[d]; 16413Sbill (*linesw[tp->t_line].l_close)(tp); 16513Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 166168Sbill dmctl(d, TURNOFF, DMSET); 16713Sbill ttyclose(tp); 16813Sbill } 16913Sbill 17013Sbill /* 17113Sbill * Read from a DH11 line. 17213Sbill */ 17313Sbill dhread(dev) 17413Sbill { 17513Sbill register struct tty *tp; 17613Sbill 17713Sbill tp = &dh11[minor(dev) & 0177]; 17813Sbill (*linesw[tp->t_line].l_read)(tp); 17913Sbill } 18013Sbill 18113Sbill /* 18213Sbill * write on a DH11 line 18313Sbill */ 18413Sbill dhwrite(dev) 18513Sbill { 18613Sbill register struct tty *tp; 18713Sbill 18813Sbill tp = &dh11[minor(dev) & 0177]; 18913Sbill (*linesw[tp->t_line].l_write)(tp); 19013Sbill } 19113Sbill 19213Sbill /* 19313Sbill * DH11 receiver interrupt. 19413Sbill */ 19513Sbill dhrint(dev) 19613Sbill { 19713Sbill register struct tty *tp; 19813Sbill register short c; 19913Sbill register struct device *addr; 200117Sbill register struct tty *tp0; 201139Sbill int s; 20213Sbill 203139Sbill s = spl6(); /* see comment in clock.c */ 20413Sbill addr = DHADDR; 20513Sbill addr += minor(dev) & 0177; 206117Sbill tp0 = &dh11[((minor(dev)&0177)<<4)]; 20713Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 208117Sbill tp = tp0 + ((c>>8)&017); 20913Sbill if (tp >= &dh11[NDH11]) 21013Sbill continue; 21113Sbill if((tp->t_state&ISOPEN)==0) { 21213Sbill wakeup((caddr_t)tp); 21313Sbill continue; 21413Sbill } 21513Sbill if (c&PERROR) 21613Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 21713Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 21813Sbill continue; 21913Sbill if (c&OVERRUN) 22013Sbill printf("O"); 22113Sbill if (c&FRERROR) /* break */ 22213Sbill if (tp->t_flags&RAW) 22313Sbill c = 0; /* null (for getty) */ 22413Sbill else 225168Sbill #ifdef IIASA 226168Sbill continue; 227168Sbill #else 228184Sbill c = tun.t_intrc; 229168Sbill #endif 230139Sbill if (tp->t_line == NETLDISC) { 231117Sbill c &= 0177; 232168Sbill BKINPUT(c, tp); 233117Sbill } else 234117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 23513Sbill } 236139Sbill splx(s); 23713Sbill } 23813Sbill 23913Sbill /* 24013Sbill * stty/gtty for DH11 24113Sbill */ 24213Sbill /*ARGSUSED*/ 24313Sbill dhioctl(dev, cmd, addr, flag) 24413Sbill caddr_t addr; 24513Sbill { 24613Sbill register struct tty *tp; 24713Sbill 24813Sbill tp = &dh11[minor(dev) & 0177]; 249113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 250113Sbill if (cmd==0) 251113Sbill return; 25213Sbill if (ttioccomm(cmd, tp, addr, dev)) { 25313Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 25413Sbill dhparam(dev); 255168Sbill } else switch(cmd) { 256168Sbill case TIOCSBRK: 257168Sbill ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017); 258168Sbill break; 259168Sbill case TIOCCBRK: 260168Sbill ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017)); 261168Sbill break; 262168Sbill case TIOCSDTR: 263168Sbill dmctl(minor(dev), DTR|RQS, DMBIS); 264168Sbill break; 265168Sbill case TIOCCDTR: 266168Sbill dmctl(minor(dev), DTR|RQS, DMBIC); 267168Sbill break; 268168Sbill default: 26913Sbill u.u_error = ENOTTY; 270168Sbill } 27113Sbill } 27213Sbill 27313Sbill /* 27413Sbill * Set parameters from open or stty into the DH hardware 27513Sbill * registers. 27613Sbill */ 27713Sbill dhparam(dev) 27813Sbill { 27913Sbill register struct tty *tp; 28013Sbill register struct device *addr; 28113Sbill register d; 282*300Sbill int s; 28313Sbill 28413Sbill d = minor(dev) & 0177; 28513Sbill tp = &dh11[d]; 28613Sbill addr = (struct device *)tp->t_addr; 287*300Sbill s = spl5(); 28813Sbill addr->un.dhcsrl = (d&017) | IENAB; 28913Sbill /* 29013Sbill * Hang up line? 29113Sbill */ 29213Sbill if ((tp->t_ispeed)==0) { 29313Sbill tp->t_state |= HUPCLS; 294168Sbill dmctl(d, TURNOFF, DMSET); 29513Sbill return; 29613Sbill } 29713Sbill d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 29813Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 29913Sbill d |= BITS6|PENABLE|HDUPLX; 30013Sbill else if (tp->t_flags&RAW) 30113Sbill d |= BITS8; 30213Sbill else 30313Sbill d |= BITS7|PENABLE; 30413Sbill if ((tp->t_flags&EVENP) == 0) 30513Sbill d |= OPAR; 30613Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 30713Sbill d |= TWOSB; 30813Sbill addr->dhlpr = d; 309*300Sbill splx(s); 31013Sbill } 31113Sbill 31213Sbill /* 31313Sbill * DH11 transmitter interrupt. 31413Sbill * Restart each line which used to be active but has 31513Sbill * terminated transmission since the last interrupt. 31613Sbill */ 31713Sbill dhxint(dev) 31813Sbill { 31913Sbill register struct tty *tp; 32013Sbill register struct device *addr; 32113Sbill register d; 32213Sbill short ttybit, bar, *sbar; 323144Sbill int s; 32413Sbill 325144Sbill s = spl6(); /* block the clock */ 32613Sbill d = minor(dev) & 0177; 32713Sbill addr = DHADDR + d; 32813Sbill addr->un.dhcsr &= (short)~XINT; 329105Sbill if (addr->un.dhcsr & NXM) { 330105Sbill addr->un.dhcsr |= CLRNXM; 331105Sbill printf("dh clr NXM\n"); 332105Sbill } 33313Sbill sbar = &dhsar[d]; 33413Sbill bar = *sbar & ~addr->dhbar; 33513Sbill d <<= 4; ttybit = 1; 33613Sbill 33713Sbill for(; bar; d++, ttybit <<= 1) { 33813Sbill if(bar&ttybit) { 33913Sbill *sbar &= ~ttybit; 34013Sbill bar &= ~ttybit; 34113Sbill tp = &dh11[d]; 342113Sbill tp->t_state &= ~BUSY; 343113Sbill if (tp->t_state&FLUSH) 344113Sbill tp->t_state &= ~FLUSH; 345113Sbill else { 346113Sbill addr->un.dhcsrl = (d&017)|IENAB; 347219Sbill ndflush(&tp->t_outq, 348219Sbill (int)addr->dhcar-UBACVT(tp->t_outq.c_cf)); 349113Sbill } 350113Sbill if (tp->t_line) 35113Sbill (*linesw[tp->t_line].l_start)(tp); 352113Sbill else 35313Sbill dhstart(tp); 35413Sbill } 35513Sbill } 356144Sbill splx(s); 35713Sbill } 35813Sbill 35913Sbill /* 36013Sbill * Start (restart) transmission on the given DH11 line. 36113Sbill */ 36213Sbill dhstart(tp) 36313Sbill register struct tty *tp; 36413Sbill { 36513Sbill register struct device *addr; 36613Sbill register short nch; 36713Sbill int s, d; 36813Sbill 36913Sbill /* 37013Sbill * If it's currently active, or delaying, 37113Sbill * no need to do anything. 37213Sbill */ 37313Sbill s = spl5(); 37413Sbill d = tp-dh11; 37513Sbill addr = (struct device *)tp->t_addr; 37613Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 37713Sbill goto out; 37813Sbill 37913Sbill /* 38013Sbill * If the writer was sleeping on output overflow, 38113Sbill * wake him when low tide is reached. 38213Sbill */ 38313Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) { 38413Sbill tp->t_state &= ~ASLEEP; 38513Sbill if (tp->t_chan) 386168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 387168Sbill else 38813Sbill wakeup((caddr_t)&tp->t_outq); 38913Sbill } 39013Sbill 39113Sbill if (tp->t_outq.c_cc == 0) 39213Sbill goto out; 39313Sbill 39413Sbill /* 39513Sbill * Find number of characters to transfer. 39613Sbill */ 39713Sbill if (tp->t_flags & RAW) { 39813Sbill nch = ndqb(&tp->t_outq, 0); 39913Sbill } else { 40013Sbill nch = ndqb(&tp->t_outq, 0200); 40113Sbill if (nch == 0) { 40213Sbill nch = getc(&tp->t_outq); 40313Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 40413Sbill tp->t_state |= TIMEOUT; 40513Sbill goto out; 40613Sbill } 40713Sbill } 40813Sbill /* 40913Sbill * If any characters were set up, start transmission; 41013Sbill */ 41113Sbill if (nch) { 41213Sbill addr->un.dhcsrl = (d&017)|IENAB; 41313Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 41413Sbill addr->dhbcr = -nch; 41513Sbill nch = 1<<(d&017); 41613Sbill addr->dhbar |= nch; 41713Sbill dhsar[d>>4] |= nch; 41813Sbill tp->t_state |= BUSY; 41913Sbill } 42013Sbill out: 42113Sbill splx(s); 42213Sbill } 42313Sbill 42413Sbill /* 42513Sbill * Stop output on a line. 42613Sbill * Assume call is made at spl6. 42713Sbill */ 42813Sbill /*ARGSUSED*/ 42913Sbill dhstop(tp, flag) 43013Sbill register struct tty *tp; 43113Sbill { 432113Sbill register struct device *addr; 433113Sbill register d, s; 43413Sbill 435113Sbill addr = (struct device *)tp->t_addr; 43613Sbill s = spl6(); 437113Sbill if (tp->t_state & BUSY) { 438113Sbill d = minor(tp->t_dev); 439113Sbill addr->un.dhcsrl = (d&017) | IENAB; 44013Sbill if ((tp->t_state&TTSTOP)==0) 44113Sbill tp->t_state |= FLUSH; 442113Sbill addr->dhbcr = -1; 443113Sbill } 44413Sbill splx(s); 44513Sbill } 44613Sbill 447117Sbill int dhsilo = 16; 448168Sbill /* 449168Sbill * Silo control is fixed strategy 450168Sbill * here, paralleling only option available 451168Sbill * on DZ-11. 452168Sbill */ 45313Sbill /*ARGSUSED*/ 454168Sbill dhtimer() 45513Sbill { 456168Sbill register d; 457117Sbill register struct device *addr; 458117Sbill 45913Sbill addr = DHADDR; d = 0; 46013Sbill do { 461117Sbill if (dhact & (1<<d)) { 462280Sbill if ((dhisilo & (1<<d)) == 0) { 463280Sbill addr->dhsilo = dhsilo; 464280Sbill dhisilo |= 1<<d; 465280Sbill } 466117Sbill dhrint(d); 467117Sbill } 468117Sbill d++; 46913Sbill addr++; 47013Sbill } while (d < (NDH11+15)/16); 47113Sbill } 472280Sbill 473280Sbill /* 474280Sbill * Reset state of driver if UBA reset was necessary. 475280Sbill * Reset the csrl and lpr registers on open lines, and 476280Sbill * restart transmitters. 477280Sbill */ 478280Sbill dhreset() 479280Sbill { 480280Sbill int d; 481280Sbill register struct tty *tp; 482280Sbill register struct device *addr; 483280Sbill 484280Sbill if (getcbase == 0) 485280Sbill return; 486280Sbill printf(" dh"); 487280Sbill dhisilo = 0; 488280Sbill ubafree(dh_ubinfo); 489280Sbill dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0); 490280Sbill cbase = (short)dh_ubinfo; 491280Sbill d = 0; 492280Sbill do { 493280Sbill addr = DHADDR + d; 494280Sbill if (dhact & (1<<d)) 495*300Sbill addr->un.dhcsr |= IENAB; 496280Sbill d++; 497280Sbill } while (d < (NDH11+15)/16); 498*300Sbill for (d = 0; d < NDH11; d++) { 499*300Sbill tp = &dh11[d]; 500*300Sbill if (tp->t_state & (ISOPEN|WOPEN)) { 501*300Sbill dhparam(d); 502*300Sbill dmctl(d, TURNON, DMSET); 503*300Sbill tp->t_state &= ~BUSY; 504*300Sbill dhstart(tp); 505*300Sbill } 506*300Sbill } 507*300Sbill dhtimer(); 508280Sbill } 509