1*1569Sbill /* dh.c 3.18 10/19/80 */ 213Sbill 31561Sbill #include "../conf/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" 2313Sbill 24144Sbill /* 25144Sbill * When running dz's using only SAE (silo alarm) on input 26144Sbill * it is necessary to call dzrint() at clock interrupt time. 27144Sbill * This is unsafe unless spl5()s in tty code are changed to 28144Sbill * spl6()s to block clock interrupts. Note that the dh driver 29144Sbill * currently in use works the same way as the dz, even though 30144Sbill * we could try to more intelligently manage its silo. 31144Sbill * Thus don't take this out if you have no dz's unless you 32144Sbill * change clock.c and dhtimer(). 33144Sbill */ 34144Sbill #define spl5 spl6 35144Sbill 361561Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree)) 3713Sbill 3813Sbill struct tty dh11[NDH11]; 39117Sbill int dhact; 40280Sbill int dhisilo; 4113Sbill int ndh11 = NDH11; 4213Sbill int dhstart(); 4313Sbill int ttrstrt(); 44280Sbill int dh_ubinfo; 45280Sbill int cbase; 46280Sbill int getcbase; 4713Sbill 4813Sbill /* 4913Sbill * Hardware control bits 5013Sbill */ 5113Sbill #define BITS6 01 5213Sbill #define BITS7 02 5313Sbill #define BITS8 03 5413Sbill #define TWOSB 04 5513Sbill #define PENABLE 020 5613Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 5713Sbill #define OPAR 040 5813Sbill #define HDUPLX 040000 5913Sbill 6013Sbill #define IENAB 030100 61105Sbill #define NXM 02000 62105Sbill #define CLRNXM 0400 6313Sbill #define PERROR 010000 6413Sbill #define FRERROR 020000 6513Sbill #define OVERRUN 040000 6613Sbill #define XINT 0100000 6713Sbill #define SSPEED 7 /* standard speed: 300 baud */ 6813Sbill 6913Sbill /* 7013Sbill * DM control bits 7113Sbill */ 7213Sbill #define TURNON 03 /* CD lead + line enable */ 7313Sbill #define TURNOFF 01 /* line enable */ 74168Sbill #define DTR 02 /* data terminal ready */ 7513Sbill #define RQS 04 /* request to send */ 7613Sbill 7713Sbill /* 7813Sbill * Software copy of last dhbar 7913Sbill */ 8013Sbill short dhsar[(NDH11+15)/16]; 8113Sbill 8213Sbill struct device 8313Sbill { 8413Sbill union { 8513Sbill short dhcsr; 8613Sbill char dhcsrl; 8713Sbill } un; 8813Sbill short dhnxch; 8913Sbill short dhlpr; 9013Sbill unsigned short dhcar; 9113Sbill short dhbcr; 9213Sbill unsigned short dhbar; 9313Sbill short dhbreak; 9413Sbill short dhsilo; 9513Sbill }; 9613Sbill 9713Sbill /* 9813Sbill * Open a DH11 line. 9913Sbill */ 10013Sbill /*ARGSUSED*/ 10113Sbill dhopen(dev, flag) 10213Sbill { 10313Sbill register struct tty *tp; 10413Sbill register d; 10513Sbill register struct device *addr; 10613Sbill int s; 10713Sbill 10813Sbill d = minor(dev) & 0177; 10913Sbill if (d >= NDH11) { 11013Sbill u.u_error = ENXIO; 11113Sbill return; 11213Sbill } 11313Sbill tp = &dh11[d]; 11413Sbill addr = DHADDR; 11513Sbill addr += d>>4; 11613Sbill tp->t_addr = (caddr_t)addr; 11713Sbill tp->t_oproc = dhstart; 11813Sbill tp->t_iproc = NULL; 11913Sbill tp->t_state |= WOPEN; 12013Sbill s = spl6(); 121117Sbill if (!getcbase) { 122117Sbill getcbase++; 123717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 124717Sbill dh_ubinfo = uballoc((caddr_t)cfree, 512+NCLIST*sizeof(struct cblock), 0); 125280Sbill cbase = (short)dh_ubinfo; 12613Sbill } 12713Sbill splx(s); 12813Sbill addr->un.dhcsr |= IENAB; 129117Sbill dhact |= (1<<(d>>4)); 13013Sbill if ((tp->t_state&ISOPEN) == 0) { 13113Sbill ttychars(tp); 132168Sbill if (tp->t_ispeed == 0) { 133168Sbill tp->t_ispeed = SSPEED; 134168Sbill tp->t_ospeed = SSPEED; 135168Sbill tp->t_flags = ODDP|EVENP|ECHO; 136168Sbill } 13713Sbill dhparam(d); 13813Sbill } 13913Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 14013Sbill u.u_error = EBUSY; 14113Sbill return; 14213Sbill } 14313Sbill dmopen(dev); 14413Sbill (*linesw[tp->t_line].l_open)(dev,tp); 14513Sbill } 14613Sbill 14713Sbill /* 14813Sbill * Close a DH11 line. 14913Sbill */ 15013Sbill /*ARGSUSED*/ 15113Sbill dhclose(dev, flag) 15213Sbill dev_t dev; 15313Sbill int flag; 15413Sbill { 15513Sbill register struct tty *tp; 15613Sbill register d; 15713Sbill 15813Sbill d = minor(dev) & 0177; 15913Sbill tp = &dh11[d]; 16013Sbill (*linesw[tp->t_line].l_close)(tp); 16113Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 162168Sbill dmctl(d, TURNOFF, DMSET); 16313Sbill ttyclose(tp); 16413Sbill } 16513Sbill 16613Sbill /* 16713Sbill * Read from a DH11 line. 16813Sbill */ 16913Sbill dhread(dev) 17013Sbill { 17113Sbill register struct tty *tp; 17213Sbill 17313Sbill tp = &dh11[minor(dev) & 0177]; 17413Sbill (*linesw[tp->t_line].l_read)(tp); 17513Sbill } 17613Sbill 17713Sbill /* 17813Sbill * write on a DH11 line 17913Sbill */ 18013Sbill dhwrite(dev) 18113Sbill { 18213Sbill register struct tty *tp; 18313Sbill 18413Sbill tp = &dh11[minor(dev) & 0177]; 18513Sbill (*linesw[tp->t_line].l_write)(tp); 18613Sbill } 18713Sbill 18813Sbill /* 18913Sbill * DH11 receiver interrupt. 19013Sbill */ 19113Sbill dhrint(dev) 19213Sbill { 19313Sbill register struct tty *tp; 19413Sbill register short c; 19513Sbill register struct device *addr; 196117Sbill register struct tty *tp0; 197139Sbill int s; 19813Sbill 199139Sbill s = spl6(); /* see comment in clock.c */ 20013Sbill addr = DHADDR; 20113Sbill addr += minor(dev) & 0177; 202117Sbill tp0 = &dh11[((minor(dev)&0177)<<4)]; 20313Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 204117Sbill tp = tp0 + ((c>>8)&017); 20513Sbill if (tp >= &dh11[NDH11]) 20613Sbill continue; 20713Sbill if((tp->t_state&ISOPEN)==0) { 20813Sbill wakeup((caddr_t)tp); 20913Sbill continue; 21013Sbill } 21113Sbill if (c&PERROR) 21213Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 21313Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 21413Sbill continue; 21513Sbill if (c&OVERRUN) 21613Sbill printf("O"); 21713Sbill if (c&FRERROR) /* break */ 21813Sbill if (tp->t_flags&RAW) 21913Sbill c = 0; /* null (for getty) */ 22013Sbill else 221168Sbill #ifdef IIASA 222168Sbill continue; 223168Sbill #else 224184Sbill c = tun.t_intrc; 225168Sbill #endif 226139Sbill if (tp->t_line == NETLDISC) { 227117Sbill c &= 0177; 228168Sbill BKINPUT(c, tp); 229117Sbill } else 230117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 23113Sbill } 232139Sbill splx(s); 23313Sbill } 23413Sbill 23513Sbill /* 23613Sbill * stty/gtty for DH11 23713Sbill */ 23813Sbill /*ARGSUSED*/ 23913Sbill dhioctl(dev, cmd, addr, flag) 24013Sbill caddr_t addr; 24113Sbill { 24213Sbill register struct tty *tp; 24313Sbill 24413Sbill tp = &dh11[minor(dev) & 0177]; 245113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 246113Sbill if (cmd==0) 247113Sbill return; 248901Sbill if (ttioctl(cmd, tp, addr, dev, flag)) { 24913Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 25013Sbill dhparam(dev); 251168Sbill } else switch(cmd) { 252168Sbill case TIOCSBRK: 253168Sbill ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017); 254168Sbill break; 255168Sbill case TIOCCBRK: 256168Sbill ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017)); 257168Sbill break; 258168Sbill case TIOCSDTR: 259168Sbill dmctl(minor(dev), DTR|RQS, DMBIS); 260168Sbill break; 261168Sbill case TIOCCDTR: 262168Sbill dmctl(minor(dev), DTR|RQS, DMBIC); 263168Sbill break; 264168Sbill default: 26513Sbill u.u_error = ENOTTY; 266168Sbill } 26713Sbill } 26813Sbill 26913Sbill /* 27013Sbill * Set parameters from open or stty into the DH hardware 27113Sbill * registers. 27213Sbill */ 27313Sbill dhparam(dev) 27413Sbill { 27513Sbill register struct tty *tp; 27613Sbill register struct device *addr; 27713Sbill register d; 278300Sbill int s; 27913Sbill 28013Sbill d = minor(dev) & 0177; 28113Sbill tp = &dh11[d]; 28213Sbill addr = (struct device *)tp->t_addr; 283300Sbill s = spl5(); 28413Sbill addr->un.dhcsrl = (d&017) | IENAB; 28513Sbill /* 28613Sbill * Hang up line? 28713Sbill */ 28813Sbill if ((tp->t_ispeed)==0) { 28913Sbill tp->t_state |= HUPCLS; 290168Sbill dmctl(d, TURNOFF, DMSET); 29113Sbill return; 29213Sbill } 29313Sbill d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 29413Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 29513Sbill d |= BITS6|PENABLE|HDUPLX; 29613Sbill else if (tp->t_flags&RAW) 29713Sbill d |= BITS8; 29813Sbill else 29913Sbill d |= BITS7|PENABLE; 30013Sbill if ((tp->t_flags&EVENP) == 0) 30113Sbill d |= OPAR; 30213Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 30313Sbill d |= TWOSB; 30413Sbill addr->dhlpr = d; 305300Sbill splx(s); 30613Sbill } 30713Sbill 30813Sbill /* 30913Sbill * DH11 transmitter interrupt. 31013Sbill * Restart each line which used to be active but has 31113Sbill * terminated transmission since the last interrupt. 31213Sbill */ 31313Sbill dhxint(dev) 31413Sbill { 31513Sbill register struct tty *tp; 31613Sbill register struct device *addr; 31713Sbill register d; 31813Sbill short ttybit, bar, *sbar; 319144Sbill int s; 32013Sbill 321144Sbill s = spl6(); /* block the clock */ 32213Sbill d = minor(dev) & 0177; 32313Sbill addr = DHADDR + d; 32413Sbill addr->un.dhcsr &= (short)~XINT; 325105Sbill if (addr->un.dhcsr & NXM) { 326105Sbill addr->un.dhcsr |= CLRNXM; 327105Sbill printf("dh clr NXM\n"); 328105Sbill } 32913Sbill sbar = &dhsar[d]; 33013Sbill bar = *sbar & ~addr->dhbar; 33113Sbill d <<= 4; ttybit = 1; 33213Sbill 33313Sbill for(; bar; d++, ttybit <<= 1) { 33413Sbill if(bar&ttybit) { 33513Sbill *sbar &= ~ttybit; 33613Sbill bar &= ~ttybit; 33713Sbill tp = &dh11[d]; 338113Sbill tp->t_state &= ~BUSY; 339113Sbill if (tp->t_state&FLUSH) 340113Sbill tp->t_state &= ~FLUSH; 341113Sbill else { 342113Sbill addr->un.dhcsrl = (d&017)|IENAB; 343219Sbill ndflush(&tp->t_outq, 344*1569Sbill (int)(short)addr->dhcar-UBACVT(tp->t_outq.c_cf)); 345113Sbill } 346113Sbill if (tp->t_line) 34713Sbill (*linesw[tp->t_line].l_start)(tp); 348113Sbill else 34913Sbill dhstart(tp); 35013Sbill } 35113Sbill } 352144Sbill splx(s); 35313Sbill } 35413Sbill 35513Sbill /* 35613Sbill * Start (restart) transmission on the given DH11 line. 35713Sbill */ 35813Sbill dhstart(tp) 35913Sbill register struct tty *tp; 36013Sbill { 36113Sbill register struct device *addr; 36213Sbill register short nch; 36313Sbill int s, d; 36413Sbill 36513Sbill /* 36613Sbill * If it's currently active, or delaying, 36713Sbill * no need to do anything. 36813Sbill */ 36913Sbill s = spl5(); 37013Sbill d = tp-dh11; 37113Sbill addr = (struct device *)tp->t_addr; 37213Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 37313Sbill goto out; 37413Sbill 37513Sbill /* 37613Sbill * If the writer was sleeping on output overflow, 37713Sbill * wake him when low tide is reached. 37813Sbill */ 379921Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) { 38013Sbill tp->t_state &= ~ASLEEP; 38113Sbill if (tp->t_chan) 382168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 383168Sbill else 38413Sbill wakeup((caddr_t)&tp->t_outq); 38513Sbill } 38613Sbill 38713Sbill if (tp->t_outq.c_cc == 0) 38813Sbill goto out; 38913Sbill 39013Sbill /* 39113Sbill * Find number of characters to transfer. 39213Sbill */ 39313Sbill if (tp->t_flags & RAW) { 39413Sbill nch = ndqb(&tp->t_outq, 0); 39513Sbill } else { 39613Sbill nch = ndqb(&tp->t_outq, 0200); 39713Sbill if (nch == 0) { 39813Sbill nch = getc(&tp->t_outq); 39913Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 40013Sbill tp->t_state |= TIMEOUT; 40113Sbill goto out; 40213Sbill } 40313Sbill } 40413Sbill /* 40513Sbill * If any characters were set up, start transmission; 40613Sbill */ 40713Sbill if (nch) { 40813Sbill addr->un.dhcsrl = (d&017)|IENAB; 40913Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 41013Sbill addr->dhbcr = -nch; 41113Sbill nch = 1<<(d&017); 41213Sbill addr->dhbar |= nch; 41313Sbill dhsar[d>>4] |= nch; 41413Sbill tp->t_state |= BUSY; 41513Sbill } 41613Sbill out: 41713Sbill splx(s); 41813Sbill } 41913Sbill 42013Sbill /* 42113Sbill * Stop output on a line. 42213Sbill * Assume call is made at spl6. 42313Sbill */ 42413Sbill /*ARGSUSED*/ 42513Sbill dhstop(tp, flag) 42613Sbill register struct tty *tp; 42713Sbill { 428113Sbill register struct device *addr; 429113Sbill register d, s; 43013Sbill 431113Sbill addr = (struct device *)tp->t_addr; 43213Sbill s = spl6(); 433113Sbill if (tp->t_state & BUSY) { 434113Sbill d = minor(tp->t_dev); 435113Sbill addr->un.dhcsrl = (d&017) | IENAB; 43613Sbill if ((tp->t_state&TTSTOP)==0) 43713Sbill tp->t_state |= FLUSH; 438113Sbill addr->dhbcr = -1; 439113Sbill } 44013Sbill splx(s); 44113Sbill } 44213Sbill 443117Sbill int dhsilo = 16; 444168Sbill /* 445168Sbill * Silo control is fixed strategy 446168Sbill * here, paralleling only option available 447168Sbill * on DZ-11. 448168Sbill */ 44913Sbill /*ARGSUSED*/ 450168Sbill dhtimer() 45113Sbill { 452168Sbill register d; 453117Sbill register struct device *addr; 454117Sbill 45513Sbill addr = DHADDR; d = 0; 45613Sbill do { 457117Sbill if (dhact & (1<<d)) { 458280Sbill if ((dhisilo & (1<<d)) == 0) { 459280Sbill addr->dhsilo = dhsilo; 460280Sbill dhisilo |= 1<<d; 461280Sbill } 462117Sbill dhrint(d); 463117Sbill } 464117Sbill d++; 46513Sbill addr++; 46613Sbill } while (d < (NDH11+15)/16); 46713Sbill } 468280Sbill 469280Sbill /* 470280Sbill * Reset state of driver if UBA reset was necessary. 471280Sbill * Reset the csrl and lpr registers on open lines, and 472280Sbill * restart transmitters. 473280Sbill */ 474280Sbill dhreset() 475280Sbill { 476280Sbill int d; 477280Sbill register struct tty *tp; 478280Sbill register struct device *addr; 479280Sbill 480280Sbill if (getcbase == 0) 481280Sbill return; 482280Sbill printf(" dh"); 483280Sbill dhisilo = 0; 484280Sbill ubafree(dh_ubinfo); 485280Sbill dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0); 486280Sbill cbase = (short)dh_ubinfo; 487280Sbill d = 0; 488280Sbill do { 489280Sbill addr = DHADDR + d; 490280Sbill if (dhact & (1<<d)) 491300Sbill addr->un.dhcsr |= IENAB; 492280Sbill d++; 493280Sbill } while (d < (NDH11+15)/16); 494300Sbill for (d = 0; d < NDH11; d++) { 495300Sbill tp = &dh11[d]; 496300Sbill if (tp->t_state & (ISOPEN|WOPEN)) { 497300Sbill dhparam(d); 498300Sbill dmctl(d, TURNON, DMSET); 499300Sbill tp->t_state &= ~BUSY; 500300Sbill dhstart(tp); 501300Sbill } 502300Sbill } 503300Sbill dhtimer(); 504280Sbill } 505