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