1*2196Stoy /* dh.c 4.9 01/19/81 */ 213Sbill 31934Swnj #include "dh.h" 41561Sbill #if NDH11 > 0 513Sbill /* 61561Sbill * DH-11 driver 71561Sbill * 81561Sbill * Loaded with dhdm if there are DM-11's otherwise with dhfdm. 91561Sbill * 101561Sbill * NB: WE HAVEN'T TESTED dhdm CODE ON VAX. 1113Sbill */ 1213Sbill 1313Sbill #include "../h/param.h" 1413Sbill #include "../h/conf.h" 1513Sbill #include "../h/dir.h" 1613Sbill #include "../h/user.h" 1713Sbill #include "../h/tty.h" 1813Sbill #include "../h/map.h" 1913Sbill #include "../h/pte.h" 2013Sbill #include "../h/uba.h" 21113Sbill #include "../h/bk.h" 221561Sbill #include "../h/clist.h" 231786Sbill #include "../h/mx.h" 2413Sbill 25144Sbill /* 26144Sbill * When running dz's using only SAE (silo alarm) on input 27144Sbill * it is necessary to call dzrint() at clock interrupt time. 28144Sbill * This is unsafe unless spl5()s in tty code are changed to 29144Sbill * spl6()s to block clock interrupts. Note that the dh driver 30144Sbill * currently in use works the same way as the dz, even though 31144Sbill * we could try to more intelligently manage its silo. 32144Sbill * Thus don't take this out if you have no dz's unless you 33144Sbill * change clock.c and dhtimer(). 34144Sbill */ 35144Sbill #define spl5 spl6 36144Sbill 371561Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree)) 3813Sbill 3913Sbill struct tty dh11[NDH11]; 40117Sbill int dhact; 41280Sbill int dhisilo; 4213Sbill int ndh11 = NDH11; 4313Sbill int dhstart(); 4413Sbill int ttrstrt(); 45280Sbill int dh_ubinfo; 46280Sbill int cbase; 47280Sbill int getcbase; 4813Sbill 4913Sbill /* 5013Sbill * Hardware control bits 5113Sbill */ 5213Sbill #define BITS6 01 5313Sbill #define BITS7 02 5413Sbill #define BITS8 03 5513Sbill #define TWOSB 04 5613Sbill #define PENABLE 020 5713Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 5813Sbill #define OPAR 040 5913Sbill #define HDUPLX 040000 6013Sbill 6113Sbill #define IENAB 030100 62105Sbill #define NXM 02000 63105Sbill #define CLRNXM 0400 6413Sbill #define PERROR 010000 6513Sbill #define FRERROR 020000 6613Sbill #define OVERRUN 040000 6713Sbill #define XINT 0100000 6813Sbill #define SSPEED 7 /* standard speed: 300 baud */ 6913Sbill 7013Sbill /* 7113Sbill * DM control bits 7213Sbill */ 7313Sbill #define TURNON 03 /* CD lead + line enable */ 7413Sbill #define TURNOFF 01 /* line enable */ 75168Sbill #define DTR 02 /* data terminal ready */ 7613Sbill #define RQS 04 /* request to send */ 7713Sbill 7813Sbill /* 7913Sbill * Software copy of last dhbar 8013Sbill */ 8113Sbill short dhsar[(NDH11+15)/16]; 8213Sbill 8313Sbill struct device 8413Sbill { 8513Sbill union { 8613Sbill short dhcsr; 8713Sbill char dhcsrl; 8813Sbill } un; 8913Sbill short dhnxch; 9013Sbill short dhlpr; 9113Sbill unsigned short dhcar; 9213Sbill short dhbcr; 9313Sbill unsigned short dhbar; 9413Sbill short dhbreak; 9513Sbill short dhsilo; 9613Sbill }; 9713Sbill 9813Sbill /* 9913Sbill * Open a DH11 line. 10013Sbill */ 10113Sbill /*ARGSUSED*/ 10213Sbill dhopen(dev, flag) 10313Sbill { 10413Sbill register struct tty *tp; 10513Sbill register d; 10613Sbill register struct device *addr; 10713Sbill int s; 10813Sbill 10913Sbill d = minor(dev) & 0177; 11013Sbill if (d >= NDH11) { 11113Sbill u.u_error = ENXIO; 11213Sbill return; 11313Sbill } 11413Sbill tp = &dh11[d]; 11513Sbill addr = DHADDR; 11613Sbill addr += d>>4; 11713Sbill tp->t_addr = (caddr_t)addr; 11813Sbill tp->t_oproc = dhstart; 11913Sbill tp->t_iproc = NULL; 12013Sbill tp->t_state |= WOPEN; 12113Sbill s = spl6(); 122117Sbill if (!getcbase) { 123117Sbill getcbase++; 124717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 125717Sbill dh_ubinfo = uballoc((caddr_t)cfree, 512+NCLIST*sizeof(struct cblock), 0); 126280Sbill cbase = (short)dh_ubinfo; 12713Sbill } 12813Sbill splx(s); 12913Sbill addr->un.dhcsr |= IENAB; 130117Sbill dhact |= (1<<(d>>4)); 13113Sbill if ((tp->t_state&ISOPEN) == 0) { 13213Sbill ttychars(tp); 133168Sbill if (tp->t_ispeed == 0) { 134168Sbill tp->t_ispeed = SSPEED; 135168Sbill tp->t_ospeed = SSPEED; 136168Sbill tp->t_flags = ODDP|EVENP|ECHO; 137168Sbill } 13813Sbill dhparam(d); 13913Sbill } 14013Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 14113Sbill u.u_error = EBUSY; 14213Sbill return; 14313Sbill } 14413Sbill dmopen(dev); 14513Sbill (*linesw[tp->t_line].l_open)(dev,tp); 14613Sbill } 14713Sbill 14813Sbill /* 14913Sbill * Close a DH11 line. 15013Sbill */ 15113Sbill /*ARGSUSED*/ 15213Sbill dhclose(dev, flag) 15313Sbill dev_t dev; 15413Sbill int flag; 15513Sbill { 15613Sbill register struct tty *tp; 15713Sbill register d; 15813Sbill 15913Sbill d = minor(dev) & 0177; 16013Sbill tp = &dh11[d]; 16113Sbill (*linesw[tp->t_line].l_close)(tp); 162*2196Stoy /* 163*2196Stoy * Turn of the break bit in case somebody did a TIOCSBRK without 164*2196Stoy * a TIOCCBRK. 165*2196Stoy */ 166*2196Stoy ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017)); 16713Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 168168Sbill dmctl(d, TURNOFF, DMSET); 16913Sbill ttyclose(tp); 17013Sbill } 17113Sbill 17213Sbill /* 17313Sbill * Read from a DH11 line. 17413Sbill */ 17513Sbill dhread(dev) 17613Sbill { 17713Sbill register struct tty *tp; 17813Sbill 17913Sbill tp = &dh11[minor(dev) & 0177]; 18013Sbill (*linesw[tp->t_line].l_read)(tp); 18113Sbill } 18213Sbill 18313Sbill /* 18413Sbill * write on a DH11 line 18513Sbill */ 18613Sbill dhwrite(dev) 18713Sbill { 18813Sbill register struct tty *tp; 18913Sbill 19013Sbill tp = &dh11[minor(dev) & 0177]; 19113Sbill (*linesw[tp->t_line].l_write)(tp); 19213Sbill } 19313Sbill 19413Sbill /* 19513Sbill * DH11 receiver interrupt. 19613Sbill */ 19713Sbill dhrint(dev) 19813Sbill { 19913Sbill register struct tty *tp; 20013Sbill register short c; 20113Sbill register struct device *addr; 202117Sbill register struct tty *tp0; 203139Sbill int s; 20413Sbill 205139Sbill s = spl6(); /* see comment in clock.c */ 20613Sbill addr = DHADDR; 20713Sbill addr += minor(dev) & 0177; 208117Sbill tp0 = &dh11[((minor(dev)&0177)<<4)]; 20913Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 210117Sbill tp = tp0 + ((c>>8)&017); 21113Sbill if (tp >= &dh11[NDH11]) 21213Sbill continue; 21313Sbill if((tp->t_state&ISOPEN)==0) { 21413Sbill wakeup((caddr_t)tp); 21513Sbill continue; 21613Sbill } 21713Sbill if (c&PERROR) 21813Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 21913Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 22013Sbill continue; 22113Sbill if (c&OVERRUN) 22213Sbill printf("O"); 22313Sbill if (c&FRERROR) /* break */ 22413Sbill if (tp->t_flags&RAW) 22513Sbill c = 0; /* null (for getty) */ 22613Sbill else 227168Sbill #ifdef IIASA 228168Sbill continue; 229168Sbill #else 230184Sbill c = tun.t_intrc; 231168Sbill #endif 232139Sbill if (tp->t_line == NETLDISC) { 233117Sbill c &= 0177; 234168Sbill BKINPUT(c, tp); 235117Sbill } else 236117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 23713Sbill } 238139Sbill splx(s); 23913Sbill } 24013Sbill 24113Sbill /* 24213Sbill * stty/gtty for DH11 24313Sbill */ 24413Sbill /*ARGSUSED*/ 24513Sbill dhioctl(dev, cmd, addr, flag) 24613Sbill caddr_t addr; 24713Sbill { 24813Sbill register struct tty *tp; 24913Sbill 25013Sbill tp = &dh11[minor(dev) & 0177]; 251113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 252113Sbill if (cmd==0) 253113Sbill return; 2541895Swnj if (ttioctl(tp, cmd, addr, flag)) { 25513Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 25613Sbill dhparam(dev); 257168Sbill } else switch(cmd) { 258168Sbill case TIOCSBRK: 259168Sbill ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017); 260168Sbill break; 261168Sbill case TIOCCBRK: 262168Sbill ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017)); 263168Sbill break; 264168Sbill case TIOCSDTR: 265168Sbill dmctl(minor(dev), DTR|RQS, DMBIS); 266168Sbill break; 267168Sbill case TIOCCDTR: 268168Sbill dmctl(minor(dev), DTR|RQS, DMBIC); 269168Sbill break; 270168Sbill default: 27113Sbill u.u_error = ENOTTY; 272168Sbill } 27313Sbill } 27413Sbill 27513Sbill /* 27613Sbill * Set parameters from open or stty into the DH hardware 27713Sbill * registers. 27813Sbill */ 27913Sbill dhparam(dev) 28013Sbill { 28113Sbill register struct tty *tp; 28213Sbill register struct device *addr; 28313Sbill register d; 284300Sbill int s; 28513Sbill 28613Sbill d = minor(dev) & 0177; 28713Sbill tp = &dh11[d]; 28813Sbill addr = (struct device *)tp->t_addr; 289300Sbill s = spl5(); 29013Sbill addr->un.dhcsrl = (d&017) | IENAB; 29113Sbill /* 29213Sbill * Hang up line? 29313Sbill */ 29413Sbill if ((tp->t_ispeed)==0) { 29513Sbill tp->t_state |= HUPCLS; 296168Sbill dmctl(d, TURNOFF, DMSET); 29713Sbill return; 29813Sbill } 29913Sbill d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 30013Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 30113Sbill d |= BITS6|PENABLE|HDUPLX; 30213Sbill else if (tp->t_flags&RAW) 30313Sbill d |= BITS8; 30413Sbill else 30513Sbill d |= BITS7|PENABLE; 30613Sbill if ((tp->t_flags&EVENP) == 0) 30713Sbill d |= OPAR; 30813Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 30913Sbill d |= TWOSB; 31013Sbill addr->dhlpr = d; 311300Sbill splx(s); 31213Sbill } 31313Sbill 31413Sbill /* 31513Sbill * DH11 transmitter interrupt. 31613Sbill * Restart each line which used to be active but has 31713Sbill * terminated transmission since the last interrupt. 31813Sbill */ 31913Sbill dhxint(dev) 32013Sbill { 32113Sbill register struct tty *tp; 32213Sbill register struct device *addr; 32313Sbill register d; 32413Sbill short ttybit, bar, *sbar; 325144Sbill int s; 32613Sbill 327144Sbill s = spl6(); /* block the clock */ 32813Sbill d = minor(dev) & 0177; 32913Sbill addr = DHADDR + d; 33013Sbill addr->un.dhcsr &= (short)~XINT; 331105Sbill if (addr->un.dhcsr & NXM) { 332105Sbill addr->un.dhcsr |= CLRNXM; 333105Sbill printf("dh clr NXM\n"); 334105Sbill } 33513Sbill sbar = &dhsar[d]; 33613Sbill bar = *sbar & ~addr->dhbar; 33713Sbill d <<= 4; ttybit = 1; 33813Sbill 33913Sbill for(; bar; d++, ttybit <<= 1) { 34013Sbill if(bar&ttybit) { 34113Sbill *sbar &= ~ttybit; 34213Sbill bar &= ~ttybit; 34313Sbill tp = &dh11[d]; 344113Sbill tp->t_state &= ~BUSY; 345113Sbill if (tp->t_state&FLUSH) 346113Sbill tp->t_state &= ~FLUSH; 347113Sbill else { 348113Sbill addr->un.dhcsrl = (d&017)|IENAB; 349219Sbill ndflush(&tp->t_outq, 3501569Sbill (int)(short)addr->dhcar-UBACVT(tp->t_outq.c_cf)); 351113Sbill } 352113Sbill if (tp->t_line) 35313Sbill (*linesw[tp->t_line].l_start)(tp); 354113Sbill else 35513Sbill dhstart(tp); 35613Sbill } 35713Sbill } 358144Sbill splx(s); 35913Sbill } 36013Sbill 36113Sbill /* 36213Sbill * Start (restart) transmission on the given DH11 line. 36313Sbill */ 36413Sbill dhstart(tp) 36513Sbill register struct tty *tp; 36613Sbill { 36713Sbill register struct device *addr; 36813Sbill register short nch; 36913Sbill int s, d; 37013Sbill 37113Sbill /* 37213Sbill * If it's currently active, or delaying, 37313Sbill * no need to do anything. 37413Sbill */ 37513Sbill s = spl5(); 37613Sbill d = tp-dh11; 37713Sbill addr = (struct device *)tp->t_addr; 37813Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 37913Sbill goto out; 38013Sbill 38113Sbill /* 38213Sbill * If the writer was sleeping on output overflow, 38313Sbill * wake him when low tide is reached. 38413Sbill */ 385921Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) { 38613Sbill tp->t_state &= ~ASLEEP; 38713Sbill if (tp->t_chan) 388168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 389168Sbill else 39013Sbill wakeup((caddr_t)&tp->t_outq); 39113Sbill } 39213Sbill 39313Sbill if (tp->t_outq.c_cc == 0) 39413Sbill goto out; 39513Sbill 39613Sbill /* 39713Sbill * Find number of characters to transfer. 39813Sbill */ 39913Sbill if (tp->t_flags & RAW) { 40013Sbill nch = ndqb(&tp->t_outq, 0); 40113Sbill } else { 40213Sbill nch = ndqb(&tp->t_outq, 0200); 40313Sbill if (nch == 0) { 40413Sbill nch = getc(&tp->t_outq); 40513Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 40613Sbill tp->t_state |= TIMEOUT; 40713Sbill goto out; 40813Sbill } 40913Sbill } 41013Sbill /* 41113Sbill * If any characters were set up, start transmission; 41213Sbill */ 41313Sbill if (nch) { 41413Sbill addr->un.dhcsrl = (d&017)|IENAB; 41513Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 41613Sbill addr->dhbcr = -nch; 41713Sbill nch = 1<<(d&017); 41813Sbill addr->dhbar |= nch; 41913Sbill dhsar[d>>4] |= nch; 42013Sbill tp->t_state |= BUSY; 42113Sbill } 42213Sbill out: 42313Sbill splx(s); 42413Sbill } 42513Sbill 42613Sbill /* 42713Sbill * Stop output on a line. 42813Sbill * Assume call is made at spl6. 42913Sbill */ 43013Sbill /*ARGSUSED*/ 43113Sbill dhstop(tp, flag) 43213Sbill register struct tty *tp; 43313Sbill { 434113Sbill register struct device *addr; 435113Sbill register d, s; 43613Sbill 437113Sbill addr = (struct device *)tp->t_addr; 43813Sbill s = spl6(); 439113Sbill if (tp->t_state & BUSY) { 440113Sbill d = minor(tp->t_dev); 441113Sbill addr->un.dhcsrl = (d&017) | IENAB; 44213Sbill if ((tp->t_state&TTSTOP)==0) 44313Sbill tp->t_state |= FLUSH; 444113Sbill addr->dhbcr = -1; 445113Sbill } 44613Sbill splx(s); 44713Sbill } 44813Sbill 449117Sbill int dhsilo = 16; 450168Sbill /* 451168Sbill * Silo control is fixed strategy 452168Sbill * here, paralleling only option available 453168Sbill * on DZ-11. 454168Sbill */ 45513Sbill /*ARGSUSED*/ 456168Sbill dhtimer() 45713Sbill { 458168Sbill register d; 459117Sbill register struct device *addr; 460117Sbill 46113Sbill addr = DHADDR; d = 0; 46213Sbill do { 463117Sbill if (dhact & (1<<d)) { 464280Sbill if ((dhisilo & (1<<d)) == 0) { 465280Sbill addr->dhsilo = dhsilo; 466280Sbill dhisilo |= 1<<d; 467280Sbill } 468117Sbill dhrint(d); 469117Sbill } 470117Sbill d++; 47113Sbill addr++; 47213Sbill } while (d < (NDH11+15)/16); 47313Sbill } 474280Sbill 475280Sbill /* 476280Sbill * Reset state of driver if UBA reset was necessary. 477280Sbill * Reset the csrl and lpr registers on open lines, and 478280Sbill * restart transmitters. 479280Sbill */ 480280Sbill dhreset() 481280Sbill { 482280Sbill int d; 483280Sbill register struct tty *tp; 484280Sbill register struct device *addr; 485280Sbill 486280Sbill if (getcbase == 0) 487280Sbill return; 488280Sbill printf(" dh"); 489280Sbill dhisilo = 0; 4902053Swnj ubarelse(&dh_ubinfo); 491280Sbill dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0); 492280Sbill cbase = (short)dh_ubinfo; 493280Sbill d = 0; 494280Sbill do { 495280Sbill addr = DHADDR + d; 496280Sbill if (dhact & (1<<d)) 497300Sbill addr->un.dhcsr |= IENAB; 498280Sbill d++; 499280Sbill } while (d < (NDH11+15)/16); 500300Sbill for (d = 0; d < NDH11; d++) { 501300Sbill tp = &dh11[d]; 502300Sbill if (tp->t_state & (ISOPEN|WOPEN)) { 503300Sbill dhparam(d); 504300Sbill dmctl(d, TURNON, DMSET); 505300Sbill tp->t_state &= ~BUSY; 506300Sbill dhstart(tp); 507300Sbill } 508300Sbill } 509300Sbill dhtimer(); 510280Sbill } 5111944Swnj #if DHDM > 0 5121944Swnj #include "../dev/dhdm.c" 5131944Swnj #else 5141944Swnj #include "../dev/dhfdm.c" 5151808Sbill #endif 5161944Swnj #endif 517