1*113Sbill /* dh.c 3.3 10/14/12 */ 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" 19*113Sbill #include "../h/bk.h" 2013Sbill 2113Sbill #define DHADDR ((struct device *)(UBA0_DEV + 0160020)) 2213Sbill #define NDH11 16 /* number of lines */ 2313Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree)) 2413Sbill 2513Sbill struct cblock { 2613Sbill struct cblock *c_next; 2713Sbill char c_info[CBSIZE]; 2813Sbill }; 2913Sbill 3013Sbill struct tty dh11[NDH11]; 3113Sbill int dhchars[(NDH11+15)/16]; 3213Sbill int ndh11 = NDH11; 3313Sbill int dhstart(); 3413Sbill int ttrstrt(); 3513Sbill int cbase; 3613Sbill extern struct cblock cfree[]; 3713Sbill 3813Sbill /* 3913Sbill * Hardware control bits 4013Sbill */ 4113Sbill #define BITS6 01 4213Sbill #define BITS7 02 4313Sbill #define BITS8 03 4413Sbill #define TWOSB 04 4513Sbill #define PENABLE 020 4613Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 4713Sbill #define OPAR 040 4813Sbill #define HDUPLX 040000 4913Sbill 5013Sbill #define IENAB 030100 51105Sbill #define NXM 02000 52105Sbill #define CLRNXM 0400 5313Sbill #define PERROR 010000 5413Sbill #define FRERROR 020000 5513Sbill #define OVERRUN 040000 5613Sbill #define XINT 0100000 5713Sbill #define SSPEED 7 /* standard speed: 300 baud */ 5813Sbill 5913Sbill #ifdef ERNIE 6013Sbill #define DHTIME 2 /* Since Berknet packets are only 100 chars */ 6113Sbill #else 6213Sbill #define DHTIME 6 6313Sbill #endif 6413Sbill extern int dhtimer(); 6513Sbill 6613Sbill /* 6713Sbill * DM control bits 6813Sbill */ 6913Sbill #define TURNON 03 /* CD lead + line enable */ 7013Sbill #define TURNOFF 01 /* line enable */ 7113Sbill #define RQS 04 /* request to send */ 7213Sbill 7313Sbill /* 7413Sbill * Software copy of last dhbar 7513Sbill */ 7613Sbill short dhsar[(NDH11+15)/16]; 7713Sbill 7813Sbill struct device 7913Sbill { 8013Sbill union { 8113Sbill short dhcsr; 8213Sbill char dhcsrl; 8313Sbill } un; 8413Sbill short dhnxch; 8513Sbill short dhlpr; 8613Sbill unsigned short dhcar; 8713Sbill short dhbcr; 8813Sbill unsigned short dhbar; 8913Sbill short dhbreak; 9013Sbill short dhsilo; 9113Sbill }; 9213Sbill 9313Sbill /* 9413Sbill * Open a DH11 line. 9513Sbill */ 9613Sbill /*ARGSUSED*/ 9713Sbill dhopen(dev, flag) 9813Sbill { 9913Sbill register struct tty *tp; 10013Sbill register d; 10113Sbill register struct device *addr; 10213Sbill static timer_on; 10313Sbill int s; 10413Sbill 10513Sbill d = minor(dev) & 0177; 10613Sbill if (d >= NDH11) { 10713Sbill u.u_error = ENXIO; 10813Sbill return; 10913Sbill } 11013Sbill tp = &dh11[d]; 11113Sbill addr = DHADDR; 11213Sbill addr += d>>4; 11313Sbill tp->t_addr = (caddr_t)addr; 11413Sbill tp->t_oproc = dhstart; 11513Sbill tp->t_iproc = NULL; 11613Sbill tp->t_state |= WOPEN; 11713Sbill s = spl6(); 11813Sbill if (!timer_on) { 11913Sbill timer_on++; 12013Sbill timeout(dhtimer, (caddr_t)0, DHTIME); 12113Sbill cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0); 12213Sbill } 12313Sbill splx(s); 12413Sbill addr->un.dhcsr |= IENAB; 12513Sbill if ((tp->t_state&ISOPEN) == 0) { 12613Sbill ttychars(tp); 12713Sbill tp->t_ispeed = SSPEED; 12813Sbill tp->t_ospeed = SSPEED; 12913Sbill tp->t_flags = ODDP|EVENP|ECHO; 13013Sbill dhparam(d); 13113Sbill } 13213Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 13313Sbill u.u_error = EBUSY; 13413Sbill return; 13513Sbill } 13613Sbill dmopen(dev); 13713Sbill (*linesw[tp->t_line].l_open)(dev,tp); 13813Sbill } 13913Sbill 14013Sbill /* 14113Sbill * Close a DH11 line. 14213Sbill */ 14313Sbill /*ARGSUSED*/ 14413Sbill dhclose(dev, flag) 14513Sbill dev_t dev; 14613Sbill int flag; 14713Sbill { 14813Sbill register struct tty *tp; 14913Sbill register d; 15013Sbill 15113Sbill d = minor(dev) & 0177; 15213Sbill tp = &dh11[d]; 15313Sbill (*linesw[tp->t_line].l_close)(tp); 15413Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 15513Sbill dmctl(d, TURNOFF); 15613Sbill ttyclose(tp); 15713Sbill } 15813Sbill 15913Sbill /* 16013Sbill * Read from a DH11 line. 16113Sbill */ 16213Sbill dhread(dev) 16313Sbill { 16413Sbill register struct tty *tp; 16513Sbill 16613Sbill tp = &dh11[minor(dev) & 0177]; 16713Sbill (*linesw[tp->t_line].l_read)(tp); 16813Sbill } 16913Sbill 17013Sbill /* 17113Sbill * write on a DH11 line 17213Sbill */ 17313Sbill dhwrite(dev) 17413Sbill { 17513Sbill register struct tty *tp; 17613Sbill 17713Sbill tp = &dh11[minor(dev) & 0177]; 17813Sbill (*linesw[tp->t_line].l_write)(tp); 17913Sbill } 18013Sbill 18113Sbill /* 18213Sbill * DH11 receiver interrupt. 18313Sbill */ 18413Sbill dhrint(dev) 18513Sbill { 18613Sbill register struct tty *tp; 18713Sbill register short c; 18813Sbill register struct device *addr; 18913Sbill 19013Sbill addr = DHADDR; 19113Sbill addr += minor(dev) & 0177; 19213Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 19313Sbill tp = &dh11[((minor(dev)&0177)<<4) + ((c>>8)&017)]; 19413Sbill dhchars[minor(dev)&0177]++; 19513Sbill if (tp >= &dh11[NDH11]) 19613Sbill continue; 19713Sbill if((tp->t_state&ISOPEN)==0) { 19813Sbill wakeup((caddr_t)tp); 19913Sbill continue; 20013Sbill } 20113Sbill if (c&PERROR) 20213Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 20313Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 20413Sbill continue; 20513Sbill if (c&OVERRUN) 20613Sbill printf("O"); 20713Sbill if (c&FRERROR) /* break */ 20813Sbill if (tp->t_flags&RAW) 20913Sbill c = 0; /* null (for getty) */ 21013Sbill else 21113Sbill c = 0177; /* DEL (intr) */ 212*113Sbill #ifdef BERKNET 213*113Sbill if (tp->t_line == BNETLDIS) { 214*113Sbill c &= 0177; 215*113Sbill NETINPUT(c, tp); 216*113Sbill } else 217*113Sbill #endif 218*113Sbill (*linesw[tp->t_line].l_rint)(c,tp); 21913Sbill } 22013Sbill } 22113Sbill 22213Sbill /* 22313Sbill * stty/gtty for DH11 22413Sbill */ 22513Sbill /*ARGSUSED*/ 22613Sbill dhioctl(dev, cmd, addr, flag) 22713Sbill caddr_t addr; 22813Sbill { 22913Sbill register struct tty *tp; 23013Sbill 23113Sbill tp = &dh11[minor(dev) & 0177]; 232*113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 233*113Sbill if (cmd==0) 234*113Sbill return; 23513Sbill if (ttioccomm(cmd, tp, addr, dev)) { 23613Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 23713Sbill dhparam(dev); 23813Sbill } else if (cmd==TIOCSBRK) { 23913Sbill /* send a break */ 24013Sbill register int linebit = 1 << (dev&017); 24113Sbill extern dhunbrk(); 24213Sbill 24313Sbill wflushtty(tp); 24413Sbill spl5(); 24513Sbill ((struct device *)tp->t_addr)->dhbreak |= linebit; 24613Sbill tp->t_state |= TIMEOUT; 24713Sbill timeout(dhunbrk, (caddr_t)tp, 25); /* 300-500 ms */ 24813Sbill while (((struct device *)tp->t_addr)->dhbreak & linebit) 24913Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 25013Sbill tp->t_state &= ~TIMEOUT; 25113Sbill spl0(); 25213Sbill flushtty(tp); 25313Sbill return; 25413Sbill } else 25513Sbill u.u_error = ENOTTY; 25613Sbill } 25713Sbill 25813Sbill dhunbrk(tp) 25913Sbill register struct tty *tp; 26013Sbill { 26113Sbill 26213Sbill ((struct device *)tp->t_addr)->dhbreak &= ~ (1 << (minor(tp->t_dev)&017)); 26313Sbill wakeup((caddr_t)&tp->t_rawq); 26413Sbill } 26513Sbill 26613Sbill /* 26713Sbill * Set parameters from open or stty into the DH hardware 26813Sbill * registers. 26913Sbill */ 27013Sbill dhparam(dev) 27113Sbill { 27213Sbill register struct tty *tp; 27313Sbill register struct device *addr; 27413Sbill register d; 27513Sbill 27613Sbill d = minor(dev) & 0177; 27713Sbill tp = &dh11[d]; 27813Sbill addr = (struct device *)tp->t_addr; 27913Sbill spl5(); 28013Sbill addr->un.dhcsrl = (d&017) | IENAB; 28113Sbill /* 28213Sbill * Hang up line? 28313Sbill */ 28413Sbill if ((tp->t_ispeed)==0) { 28513Sbill tp->t_state |= HUPCLS; 28613Sbill dmctl(d, TURNOFF); 28713Sbill return; 28813Sbill } 28913Sbill d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 29013Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 29113Sbill d |= BITS6|PENABLE|HDUPLX; 29213Sbill else if (tp->t_flags&RAW) 29313Sbill d |= BITS8; 29413Sbill else 29513Sbill d |= BITS7|PENABLE; 29613Sbill if ((tp->t_flags&EVENP) == 0) 29713Sbill d |= OPAR; 29813Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 29913Sbill d |= TWOSB; 30013Sbill addr->dhlpr = d; 30113Sbill spl0(); 30213Sbill } 30313Sbill 30413Sbill /* 30513Sbill * DH11 transmitter interrupt. 30613Sbill * Restart each line which used to be active but has 30713Sbill * terminated transmission since the last interrupt. 30813Sbill */ 30913Sbill dhxint(dev) 31013Sbill { 31113Sbill register struct tty *tp; 31213Sbill register struct device *addr; 31313Sbill register d; 31413Sbill short ttybit, bar, *sbar; 31513Sbill 31613Sbill d = minor(dev) & 0177; 31713Sbill addr = DHADDR + d; 31813Sbill addr->un.dhcsr &= (short)~XINT; 319105Sbill if (addr->un.dhcsr & NXM) { 320105Sbill addr->un.dhcsr |= CLRNXM; 321105Sbill printf("dh clr NXM\n"); 322105Sbill } 32313Sbill sbar = &dhsar[d]; 32413Sbill bar = *sbar & ~addr->dhbar; 32513Sbill d <<= 4; ttybit = 1; 32613Sbill 32713Sbill for(; bar; d++, ttybit <<= 1) { 32813Sbill if(bar&ttybit) { 32913Sbill *sbar &= ~ttybit; 33013Sbill bar &= ~ttybit; 33113Sbill tp = &dh11[d]; 332*113Sbill tp->t_state &= ~BUSY; 333*113Sbill if (tp->t_state&FLUSH) 334*113Sbill tp->t_state &= ~FLUSH; 335*113Sbill else { 336*113Sbill addr->un.dhcsrl = (d&017)|IENAB; 337*113Sbill ndflush(&tp->t_outq, addr->dhcar-UBACVT(tp->t_outq.c_cf)); 338*113Sbill } 339*113Sbill if (tp->t_line) 34013Sbill (*linesw[tp->t_line].l_start)(tp); 341*113Sbill else 34213Sbill dhstart(tp); 34313Sbill } 34413Sbill } 34513Sbill } 34613Sbill 34713Sbill /* 34813Sbill * Start (restart) transmission on the given DH11 line. 34913Sbill */ 35013Sbill dhstart(tp) 35113Sbill register struct tty *tp; 35213Sbill { 35313Sbill register struct device *addr; 35413Sbill register short nch; 35513Sbill int s, d; 35613Sbill 35713Sbill /* 35813Sbill * If it's currently active, or delaying, 35913Sbill * no need to do anything. 36013Sbill */ 36113Sbill s = spl5(); 36213Sbill d = tp-dh11; 36313Sbill addr = (struct device *)tp->t_addr; 36413Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 36513Sbill goto out; 36613Sbill 36713Sbill /* 36813Sbill * If the writer was sleeping on output overflow, 36913Sbill * wake him when low tide is reached. 37013Sbill */ 37113Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) { 37213Sbill tp->t_state &= ~ASLEEP; 37313Sbill if (tp->t_chan) 37413Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); else 37513Sbill wakeup((caddr_t)&tp->t_outq); 37613Sbill } 37713Sbill 37813Sbill if (tp->t_outq.c_cc == 0) 37913Sbill goto out; 38013Sbill 38113Sbill /* 38213Sbill * Find number of characters to transfer. 38313Sbill */ 38413Sbill if (tp->t_flags & RAW) { 38513Sbill nch = ndqb(&tp->t_outq, 0); 38613Sbill } else { 38713Sbill nch = ndqb(&tp->t_outq, 0200); 38813Sbill if (nch == 0) { 38913Sbill nch = getc(&tp->t_outq); 39013Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 39113Sbill tp->t_state |= TIMEOUT; 39213Sbill goto out; 39313Sbill } 39413Sbill } 39513Sbill /* 39613Sbill * If any characters were set up, start transmission; 39713Sbill */ 39813Sbill if (nch) { 39913Sbill addr->un.dhcsrl = (d&017)|IENAB; 40013Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 40113Sbill addr->dhbcr = -nch; 40213Sbill nch = 1<<(d&017); 40313Sbill addr->dhbar |= nch; 40413Sbill dhsar[d>>4] |= nch; 40513Sbill tp->t_state |= BUSY; 40613Sbill } 40713Sbill out: 40813Sbill splx(s); 40913Sbill } 41013Sbill 41113Sbill 41213Sbill /* 41313Sbill * Stop output on a line. 41413Sbill * Assume call is made at spl6. 41513Sbill */ 41613Sbill /*ARGSUSED*/ 41713Sbill dhstop(tp, flag) 41813Sbill register struct tty *tp; 41913Sbill { 420*113Sbill register struct device *addr; 421*113Sbill register d, s; 42213Sbill 423*113Sbill addr = (struct device *)tp->t_addr; 42413Sbill s = spl6(); 425*113Sbill if (tp->t_state & BUSY) { 426*113Sbill d = minor(tp->t_dev); 427*113Sbill addr->un.dhcsrl = (d&017) | IENAB; 42813Sbill if ((tp->t_state&TTSTOP)==0) 42913Sbill tp->t_state |= FLUSH; 430*113Sbill addr->dhbcr = -1; 431*113Sbill } 43213Sbill splx(s); 43313Sbill } 43413Sbill 435*113Sbill int minsilo = 16; 43613Sbill /*ARGSUSED*/ 43713Sbill dhtimer(dev) 43813Sbill { 43913Sbill register d,cc; 44013Sbill register struct device *addr; 44113Sbill addr = DHADDR; d = 0; 44213Sbill do { 44313Sbill cc = dhchars[d]; 44413Sbill dhchars[d] = 0; 44513Sbill if (cc > 8*DHTIME) 44613Sbill cc = 32; else 44713Sbill if (cc > 3*DHTIME) 44813Sbill cc = 16; else 449*113Sbill cc = minsilo; 45013Sbill addr->dhsilo = cc; 45113Sbill addr++; 45213Sbill dhrint(d++); 45313Sbill } while (d < (NDH11+15)/16); 45413Sbill timeout(dhtimer, (caddr_t)0, DHTIME); 45513Sbill } 456