1*117Sbill /* dh.c 3.4 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" 19113Sbill #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]; 31*117Sbill int dhact; 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 /* 6013Sbill * DM control bits 6113Sbill */ 6213Sbill #define TURNON 03 /* CD lead + line enable */ 6313Sbill #define TURNOFF 01 /* line enable */ 6413Sbill #define RQS 04 /* request to send */ 6513Sbill 6613Sbill /* 6713Sbill * Software copy of last dhbar 6813Sbill */ 6913Sbill short dhsar[(NDH11+15)/16]; 7013Sbill 7113Sbill struct device 7213Sbill { 7313Sbill union { 7413Sbill short dhcsr; 7513Sbill char dhcsrl; 7613Sbill } un; 7713Sbill short dhnxch; 7813Sbill short dhlpr; 7913Sbill unsigned short dhcar; 8013Sbill short dhbcr; 8113Sbill unsigned short dhbar; 8213Sbill short dhbreak; 8313Sbill short dhsilo; 8413Sbill }; 8513Sbill 8613Sbill /* 8713Sbill * Open a DH11 line. 8813Sbill */ 8913Sbill /*ARGSUSED*/ 9013Sbill dhopen(dev, flag) 9113Sbill { 9213Sbill register struct tty *tp; 9313Sbill register d; 9413Sbill register struct device *addr; 95*117Sbill static getcbase; 9613Sbill int s; 9713Sbill 9813Sbill d = minor(dev) & 0177; 9913Sbill if (d >= NDH11) { 10013Sbill u.u_error = ENXIO; 10113Sbill return; 10213Sbill } 10313Sbill tp = &dh11[d]; 10413Sbill addr = DHADDR; 10513Sbill addr += d>>4; 10613Sbill tp->t_addr = (caddr_t)addr; 10713Sbill tp->t_oproc = dhstart; 10813Sbill tp->t_iproc = NULL; 10913Sbill tp->t_state |= WOPEN; 11013Sbill s = spl6(); 111*117Sbill if (!getcbase) { 112*117Sbill getcbase++; 11313Sbill cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0); 11413Sbill } 11513Sbill splx(s); 11613Sbill addr->un.dhcsr |= IENAB; 117*117Sbill dhact |= (1<<(d>>4)); 11813Sbill if ((tp->t_state&ISOPEN) == 0) { 11913Sbill ttychars(tp); 12013Sbill tp->t_ispeed = SSPEED; 12113Sbill tp->t_ospeed = SSPEED; 12213Sbill tp->t_flags = ODDP|EVENP|ECHO; 12313Sbill dhparam(d); 12413Sbill } 12513Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 12613Sbill u.u_error = EBUSY; 12713Sbill return; 12813Sbill } 12913Sbill dmopen(dev); 13013Sbill (*linesw[tp->t_line].l_open)(dev,tp); 13113Sbill } 13213Sbill 13313Sbill /* 13413Sbill * Close a DH11 line. 13513Sbill */ 13613Sbill /*ARGSUSED*/ 13713Sbill dhclose(dev, flag) 13813Sbill dev_t dev; 13913Sbill int flag; 14013Sbill { 14113Sbill register struct tty *tp; 14213Sbill register d; 14313Sbill 14413Sbill d = minor(dev) & 0177; 14513Sbill tp = &dh11[d]; 14613Sbill (*linesw[tp->t_line].l_close)(tp); 14713Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 14813Sbill dmctl(d, TURNOFF); 14913Sbill ttyclose(tp); 15013Sbill } 15113Sbill 15213Sbill /* 15313Sbill * Read from a DH11 line. 15413Sbill */ 15513Sbill dhread(dev) 15613Sbill { 15713Sbill register struct tty *tp; 15813Sbill 15913Sbill tp = &dh11[minor(dev) & 0177]; 16013Sbill (*linesw[tp->t_line].l_read)(tp); 16113Sbill } 16213Sbill 16313Sbill /* 16413Sbill * write on a DH11 line 16513Sbill */ 16613Sbill dhwrite(dev) 16713Sbill { 16813Sbill register struct tty *tp; 16913Sbill 17013Sbill tp = &dh11[minor(dev) & 0177]; 17113Sbill (*linesw[tp->t_line].l_write)(tp); 17213Sbill } 17313Sbill 17413Sbill /* 17513Sbill * DH11 receiver interrupt. 17613Sbill */ 17713Sbill dhrint(dev) 17813Sbill { 17913Sbill register struct tty *tp; 18013Sbill register short c; 18113Sbill register struct device *addr; 182*117Sbill register struct tty *tp0; 18313Sbill 18413Sbill addr = DHADDR; 18513Sbill addr += minor(dev) & 0177; 186*117Sbill tp0 = &dh11[((minor(dev)&0177)<<4)]; 18713Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 188*117Sbill tp = tp0 + ((c>>8)&017); 18913Sbill if (tp >= &dh11[NDH11]) 19013Sbill continue; 19113Sbill if((tp->t_state&ISOPEN)==0) { 19213Sbill wakeup((caddr_t)tp); 19313Sbill continue; 19413Sbill } 19513Sbill if (c&PERROR) 19613Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 19713Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 19813Sbill continue; 19913Sbill if (c&OVERRUN) 20013Sbill printf("O"); 20113Sbill if (c&FRERROR) /* break */ 20213Sbill if (tp->t_flags&RAW) 20313Sbill c = 0; /* null (for getty) */ 20413Sbill else 20513Sbill c = 0177; /* DEL (intr) */ 206113Sbill #ifdef BERKNET 207*117Sbill if (tp->t_line == BNETLDIS) { 208*117Sbill c &= 0177; 209*117Sbill NETINPUT(c, tp); 210*117Sbill } else 211113Sbill #endif 212*117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 21313Sbill } 21413Sbill } 21513Sbill 21613Sbill /* 21713Sbill * stty/gtty for DH11 21813Sbill */ 21913Sbill /*ARGSUSED*/ 22013Sbill dhioctl(dev, cmd, addr, flag) 22113Sbill caddr_t addr; 22213Sbill { 22313Sbill register struct tty *tp; 22413Sbill 22513Sbill tp = &dh11[minor(dev) & 0177]; 226113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 227113Sbill if (cmd==0) 228113Sbill return; 22913Sbill if (ttioccomm(cmd, tp, addr, dev)) { 23013Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 23113Sbill dhparam(dev); 23213Sbill } else if (cmd==TIOCSBRK) { 23313Sbill /* send a break */ 23413Sbill register int linebit = 1 << (dev&017); 23513Sbill extern dhunbrk(); 23613Sbill 23713Sbill wflushtty(tp); 23813Sbill spl5(); 23913Sbill ((struct device *)tp->t_addr)->dhbreak |= linebit; 24013Sbill tp->t_state |= TIMEOUT; 24113Sbill timeout(dhunbrk, (caddr_t)tp, 25); /* 300-500 ms */ 24213Sbill while (((struct device *)tp->t_addr)->dhbreak & linebit) 24313Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 24413Sbill tp->t_state &= ~TIMEOUT; 24513Sbill spl0(); 24613Sbill flushtty(tp); 24713Sbill return; 24813Sbill } else 24913Sbill u.u_error = ENOTTY; 25013Sbill } 25113Sbill 25213Sbill dhunbrk(tp) 25313Sbill register struct tty *tp; 25413Sbill { 25513Sbill 25613Sbill ((struct device *)tp->t_addr)->dhbreak &= ~ (1 << (minor(tp->t_dev)&017)); 25713Sbill wakeup((caddr_t)&tp->t_rawq); 25813Sbill } 25913Sbill 26013Sbill /* 26113Sbill * Set parameters from open or stty into the DH hardware 26213Sbill * registers. 26313Sbill */ 26413Sbill dhparam(dev) 26513Sbill { 26613Sbill register struct tty *tp; 26713Sbill register struct device *addr; 26813Sbill register d; 26913Sbill 27013Sbill d = minor(dev) & 0177; 27113Sbill tp = &dh11[d]; 27213Sbill addr = (struct device *)tp->t_addr; 27313Sbill spl5(); 27413Sbill addr->un.dhcsrl = (d&017) | IENAB; 27513Sbill /* 27613Sbill * Hang up line? 27713Sbill */ 27813Sbill if ((tp->t_ispeed)==0) { 27913Sbill tp->t_state |= HUPCLS; 28013Sbill dmctl(d, TURNOFF); 28113Sbill return; 28213Sbill } 28313Sbill d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 28413Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 28513Sbill d |= BITS6|PENABLE|HDUPLX; 28613Sbill else if (tp->t_flags&RAW) 28713Sbill d |= BITS8; 28813Sbill else 28913Sbill d |= BITS7|PENABLE; 29013Sbill if ((tp->t_flags&EVENP) == 0) 29113Sbill d |= OPAR; 29213Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 29313Sbill d |= TWOSB; 29413Sbill addr->dhlpr = d; 29513Sbill spl0(); 29613Sbill } 29713Sbill 29813Sbill /* 29913Sbill * DH11 transmitter interrupt. 30013Sbill * Restart each line which used to be active but has 30113Sbill * terminated transmission since the last interrupt. 30213Sbill */ 30313Sbill dhxint(dev) 30413Sbill { 30513Sbill register struct tty *tp; 30613Sbill register struct device *addr; 30713Sbill register d; 30813Sbill short ttybit, bar, *sbar; 30913Sbill 31013Sbill d = minor(dev) & 0177; 31113Sbill addr = DHADDR + d; 31213Sbill addr->un.dhcsr &= (short)~XINT; 313105Sbill if (addr->un.dhcsr & NXM) { 314105Sbill addr->un.dhcsr |= CLRNXM; 315105Sbill printf("dh clr NXM\n"); 316105Sbill } 31713Sbill sbar = &dhsar[d]; 31813Sbill bar = *sbar & ~addr->dhbar; 31913Sbill d <<= 4; ttybit = 1; 32013Sbill 32113Sbill for(; bar; d++, ttybit <<= 1) { 32213Sbill if(bar&ttybit) { 32313Sbill *sbar &= ~ttybit; 32413Sbill bar &= ~ttybit; 32513Sbill tp = &dh11[d]; 326113Sbill tp->t_state &= ~BUSY; 327113Sbill if (tp->t_state&FLUSH) 328113Sbill tp->t_state &= ~FLUSH; 329113Sbill else { 330113Sbill addr->un.dhcsrl = (d&017)|IENAB; 331113Sbill ndflush(&tp->t_outq, addr->dhcar-UBACVT(tp->t_outq.c_cf)); 332113Sbill } 333113Sbill if (tp->t_line) 33413Sbill (*linesw[tp->t_line].l_start)(tp); 335113Sbill else 33613Sbill dhstart(tp); 33713Sbill } 33813Sbill } 33913Sbill } 34013Sbill 34113Sbill /* 34213Sbill * Start (restart) transmission on the given DH11 line. 34313Sbill */ 34413Sbill dhstart(tp) 34513Sbill register struct tty *tp; 34613Sbill { 34713Sbill register struct device *addr; 34813Sbill register short nch; 34913Sbill int s, d; 35013Sbill 35113Sbill /* 35213Sbill * If it's currently active, or delaying, 35313Sbill * no need to do anything. 35413Sbill */ 35513Sbill s = spl5(); 35613Sbill d = tp-dh11; 35713Sbill addr = (struct device *)tp->t_addr; 35813Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 35913Sbill goto out; 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 * Find number of characters to transfer. 37713Sbill */ 37813Sbill if (tp->t_flags & RAW) { 37913Sbill nch = ndqb(&tp->t_outq, 0); 38013Sbill } else { 38113Sbill nch = ndqb(&tp->t_outq, 0200); 38213Sbill if (nch == 0) { 38313Sbill nch = getc(&tp->t_outq); 38413Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 38513Sbill tp->t_state |= TIMEOUT; 38613Sbill goto out; 38713Sbill } 38813Sbill } 38913Sbill /* 39013Sbill * If any characters were set up, start transmission; 39113Sbill */ 39213Sbill if (nch) { 39313Sbill addr->un.dhcsrl = (d&017)|IENAB; 39413Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 39513Sbill addr->dhbcr = -nch; 39613Sbill nch = 1<<(d&017); 39713Sbill addr->dhbar |= nch; 39813Sbill dhsar[d>>4] |= nch; 39913Sbill tp->t_state |= BUSY; 40013Sbill } 40113Sbill out: 40213Sbill splx(s); 40313Sbill } 40413Sbill 40513Sbill 40613Sbill /* 40713Sbill * Stop output on a line. 40813Sbill * Assume call is made at spl6. 40913Sbill */ 41013Sbill /*ARGSUSED*/ 41113Sbill dhstop(tp, flag) 41213Sbill register struct tty *tp; 41313Sbill { 414113Sbill register struct device *addr; 415113Sbill register d, s; 41613Sbill 417113Sbill addr = (struct device *)tp->t_addr; 41813Sbill s = spl6(); 419113Sbill if (tp->t_state & BUSY) { 420113Sbill d = minor(tp->t_dev); 421113Sbill addr->un.dhcsrl = (d&017) | IENAB; 42213Sbill if ((tp->t_state&TTSTOP)==0) 42313Sbill tp->t_state |= FLUSH; 424113Sbill addr->dhbcr = -1; 425113Sbill } 42613Sbill splx(s); 42713Sbill } 42813Sbill 429*117Sbill int dhsilo = 16; 43013Sbill /*ARGSUSED*/ 43113Sbill dhtimer(dev) 43213Sbill { 433*117Sbill register d,cc; 434*117Sbill register struct device *addr; 435*117Sbill 43613Sbill addr = DHADDR; d = 0; 43713Sbill do { 438*117Sbill if (dhact & (1<<d)) { 439*117Sbill addr->dhsilo = dhsilo; 440*117Sbill dhrint(d); 441*117Sbill } 442*117Sbill d++; 44313Sbill addr++; 44413Sbill } while (d < (NDH11+15)/16); 44513Sbill } 446