1*168Sbill /* dh.c 3.6 5/9/80 */ 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 21144Sbill /* 22144Sbill * When running dz's using only SAE (silo alarm) on input 23144Sbill * it is necessary to call dzrint() at clock interrupt time. 24144Sbill * This is unsafe unless spl5()s in tty code are changed to 25144Sbill * spl6()s to block clock interrupts. Note that the dh driver 26144Sbill * currently in use works the same way as the dz, even though 27144Sbill * we could try to more intelligently manage its silo. 28144Sbill * Thus don't take this out if you have no dz's unless you 29144Sbill * change clock.c and dhtimer(). 30144Sbill */ 31144Sbill #define spl5 spl6 32144Sbill 3313Sbill #define DHADDR ((struct device *)(UBA0_DEV + 0160020)) 3413Sbill #define NDH11 16 /* number of lines */ 3513Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree)) 3613Sbill 3713Sbill struct cblock { 3813Sbill struct cblock *c_next; 3913Sbill char c_info[CBSIZE]; 4013Sbill }; 4113Sbill 4213Sbill struct tty dh11[NDH11]; 43117Sbill int dhact; 4413Sbill int ndh11 = NDH11; 4513Sbill int dhstart(); 4613Sbill int ttrstrt(); 4713Sbill int cbase; 4813Sbill extern struct cblock cfree[]; 4913Sbill 5013Sbill /* 5113Sbill * Hardware control bits 5213Sbill */ 5313Sbill #define BITS6 01 5413Sbill #define BITS7 02 5513Sbill #define BITS8 03 5613Sbill #define TWOSB 04 5713Sbill #define PENABLE 020 5813Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 5913Sbill #define OPAR 040 6013Sbill #define HDUPLX 040000 6113Sbill 6213Sbill #define IENAB 030100 63105Sbill #define NXM 02000 64105Sbill #define CLRNXM 0400 6513Sbill #define PERROR 010000 6613Sbill #define FRERROR 020000 6713Sbill #define OVERRUN 040000 6813Sbill #define XINT 0100000 6913Sbill #define SSPEED 7 /* standard speed: 300 baud */ 7013Sbill 7113Sbill /* 7213Sbill * DM control bits 7313Sbill */ 7413Sbill #define TURNON 03 /* CD lead + line enable */ 7513Sbill #define TURNOFF 01 /* line enable */ 76*168Sbill #define DTR 02 /* data terminal ready */ 7713Sbill #define RQS 04 /* request to send */ 7813Sbill 7913Sbill /* 8013Sbill * Software copy of last dhbar 8113Sbill */ 8213Sbill short dhsar[(NDH11+15)/16]; 8313Sbill 8413Sbill struct device 8513Sbill { 8613Sbill union { 8713Sbill short dhcsr; 8813Sbill char dhcsrl; 8913Sbill } un; 9013Sbill short dhnxch; 9113Sbill short dhlpr; 9213Sbill unsigned short dhcar; 9313Sbill short dhbcr; 9413Sbill unsigned short dhbar; 9513Sbill short dhbreak; 9613Sbill short dhsilo; 9713Sbill }; 9813Sbill 9913Sbill /* 10013Sbill * Open a DH11 line. 10113Sbill */ 10213Sbill /*ARGSUSED*/ 10313Sbill dhopen(dev, flag) 10413Sbill { 10513Sbill register struct tty *tp; 10613Sbill register d; 10713Sbill register struct device *addr; 108117Sbill static getcbase; 10913Sbill int s; 11013Sbill 11113Sbill d = minor(dev) & 0177; 11213Sbill if (d >= NDH11) { 11313Sbill u.u_error = ENXIO; 11413Sbill return; 11513Sbill } 11613Sbill tp = &dh11[d]; 11713Sbill addr = DHADDR; 11813Sbill addr += d>>4; 11913Sbill tp->t_addr = (caddr_t)addr; 12013Sbill tp->t_oproc = dhstart; 12113Sbill tp->t_iproc = NULL; 12213Sbill tp->t_state |= WOPEN; 12313Sbill s = spl6(); 124117Sbill if (!getcbase) { 125117Sbill getcbase++; 12613Sbill cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0); 12713Sbill } 12813Sbill splx(s); 12913Sbill addr->un.dhcsr |= IENAB; 130117Sbill dhact |= (1<<(d>>4)); 13113Sbill if ((tp->t_state&ISOPEN) == 0) { 13213Sbill ttychars(tp); 133*168Sbill if (tp->t_ispeed == 0) { 134*168Sbill tp->t_ispeed = SSPEED; 135*168Sbill tp->t_ospeed = SSPEED; 136*168Sbill tp->t_flags = ODDP|EVENP|ECHO; 137*168Sbill } 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); 16213Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 163*168Sbill dmctl(d, TURNOFF, DMSET); 16413Sbill ttyclose(tp); 16513Sbill } 16613Sbill 16713Sbill /* 16813Sbill * Read from a DH11 line. 16913Sbill */ 17013Sbill dhread(dev) 17113Sbill { 17213Sbill register struct tty *tp; 17313Sbill 17413Sbill tp = &dh11[minor(dev) & 0177]; 17513Sbill (*linesw[tp->t_line].l_read)(tp); 17613Sbill } 17713Sbill 17813Sbill /* 17913Sbill * write on a DH11 line 18013Sbill */ 18113Sbill dhwrite(dev) 18213Sbill { 18313Sbill register struct tty *tp; 18413Sbill 18513Sbill tp = &dh11[minor(dev) & 0177]; 18613Sbill (*linesw[tp->t_line].l_write)(tp); 18713Sbill } 18813Sbill 18913Sbill /* 19013Sbill * DH11 receiver interrupt. 19113Sbill */ 19213Sbill dhrint(dev) 19313Sbill { 19413Sbill register struct tty *tp; 19513Sbill register short c; 19613Sbill register struct device *addr; 197117Sbill register struct tty *tp0; 198139Sbill int s; 19913Sbill 200139Sbill s = spl6(); /* see comment in clock.c */ 20113Sbill addr = DHADDR; 20213Sbill addr += minor(dev) & 0177; 203117Sbill tp0 = &dh11[((minor(dev)&0177)<<4)]; 20413Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 205117Sbill tp = tp0 + ((c>>8)&017); 20613Sbill if (tp >= &dh11[NDH11]) 20713Sbill continue; 20813Sbill if((tp->t_state&ISOPEN)==0) { 20913Sbill wakeup((caddr_t)tp); 21013Sbill continue; 21113Sbill } 21213Sbill if (c&PERROR) 21313Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 21413Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 21513Sbill continue; 21613Sbill if (c&OVERRUN) 21713Sbill printf("O"); 21813Sbill if (c&FRERROR) /* break */ 21913Sbill if (tp->t_flags&RAW) 22013Sbill c = 0; /* null (for getty) */ 22113Sbill else 222*168Sbill #ifdef IIASA 223*168Sbill continue; 224*168Sbill #else 225*168Sbill c = 0177; /* tun.t_intrc? */ 226*168Sbill #endif 227139Sbill if (tp->t_line == NETLDISC) { 228117Sbill c &= 0177; 229*168Sbill BKINPUT(c, tp); 230117Sbill } else 231117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 23213Sbill } 233139Sbill splx(s); 23413Sbill } 23513Sbill 23613Sbill /* 23713Sbill * stty/gtty for DH11 23813Sbill */ 23913Sbill /*ARGSUSED*/ 24013Sbill dhioctl(dev, cmd, addr, flag) 24113Sbill caddr_t addr; 24213Sbill { 24313Sbill register struct tty *tp; 24413Sbill 24513Sbill tp = &dh11[minor(dev) & 0177]; 246113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 247113Sbill if (cmd==0) 248113Sbill return; 24913Sbill if (ttioccomm(cmd, tp, addr, dev)) { 25013Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 25113Sbill dhparam(dev); 252*168Sbill } else switch(cmd) { 253*168Sbill case TIOCSBRK: 254*168Sbill ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017); 255*168Sbill break; 256*168Sbill case TIOCCBRK: 257*168Sbill ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017)); 258*168Sbill break; 259*168Sbill case TIOCSDTR: 260*168Sbill dmctl(minor(dev), DTR|RQS, DMBIS); 261*168Sbill break; 262*168Sbill case TIOCCDTR: 263*168Sbill dmctl(minor(dev), DTR|RQS, DMBIC); 264*168Sbill break; 265*168Sbill default: 26613Sbill u.u_error = ENOTTY; 267*168Sbill } 26813Sbill } 26913Sbill 27013Sbill /* 27113Sbill * Set parameters from open or stty into the DH hardware 27213Sbill * registers. 27313Sbill */ 27413Sbill dhparam(dev) 27513Sbill { 27613Sbill register struct tty *tp; 27713Sbill register struct device *addr; 27813Sbill register d; 27913Sbill 28013Sbill d = minor(dev) & 0177; 28113Sbill tp = &dh11[d]; 28213Sbill addr = (struct device *)tp->t_addr; 28313Sbill 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; 290*168Sbill 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; 30513Sbill spl0(); 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; 343*168Sbill ndflush(&tp->t_outq, (int)addr->dhcar-UBACVT(tp->t_outq.c_cf)); 344113Sbill } 345113Sbill if (tp->t_line) 34613Sbill (*linesw[tp->t_line].l_start)(tp); 347113Sbill else 34813Sbill dhstart(tp); 34913Sbill } 35013Sbill } 351144Sbill splx(s); 35213Sbill } 35313Sbill 35413Sbill /* 35513Sbill * Start (restart) transmission on the given DH11 line. 35613Sbill */ 35713Sbill dhstart(tp) 35813Sbill register struct tty *tp; 35913Sbill { 36013Sbill register struct device *addr; 36113Sbill register short nch; 36213Sbill int s, d; 36313Sbill 36413Sbill /* 36513Sbill * If it's currently active, or delaying, 36613Sbill * no need to do anything. 36713Sbill */ 36813Sbill s = spl5(); 36913Sbill d = tp-dh11; 37013Sbill addr = (struct device *)tp->t_addr; 37113Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 37213Sbill goto out; 37313Sbill 37413Sbill /* 37513Sbill * If the writer was sleeping on output overflow, 37613Sbill * wake him when low tide is reached. 37713Sbill */ 37813Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) { 37913Sbill tp->t_state &= ~ASLEEP; 38013Sbill if (tp->t_chan) 381*168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 382*168Sbill else 38313Sbill wakeup((caddr_t)&tp->t_outq); 38413Sbill } 38513Sbill 38613Sbill if (tp->t_outq.c_cc == 0) 38713Sbill goto out; 38813Sbill 38913Sbill /* 39013Sbill * Find number of characters to transfer. 39113Sbill */ 39213Sbill if (tp->t_flags & RAW) { 39313Sbill nch = ndqb(&tp->t_outq, 0); 39413Sbill } else { 39513Sbill nch = ndqb(&tp->t_outq, 0200); 39613Sbill if (nch == 0) { 39713Sbill nch = getc(&tp->t_outq); 39813Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 39913Sbill tp->t_state |= TIMEOUT; 40013Sbill goto out; 40113Sbill } 40213Sbill } 40313Sbill /* 40413Sbill * If any characters were set up, start transmission; 40513Sbill */ 40613Sbill if (nch) { 40713Sbill addr->un.dhcsrl = (d&017)|IENAB; 40813Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 40913Sbill addr->dhbcr = -nch; 41013Sbill nch = 1<<(d&017); 41113Sbill addr->dhbar |= nch; 41213Sbill dhsar[d>>4] |= nch; 41313Sbill tp->t_state |= BUSY; 41413Sbill } 41513Sbill out: 41613Sbill splx(s); 41713Sbill } 41813Sbill 41913Sbill /* 42013Sbill * Stop output on a line. 42113Sbill * Assume call is made at spl6. 42213Sbill */ 42313Sbill /*ARGSUSED*/ 42413Sbill dhstop(tp, flag) 42513Sbill register struct tty *tp; 42613Sbill { 427113Sbill register struct device *addr; 428113Sbill register d, s; 42913Sbill 430113Sbill addr = (struct device *)tp->t_addr; 43113Sbill s = spl6(); 432113Sbill if (tp->t_state & BUSY) { 433113Sbill d = minor(tp->t_dev); 434113Sbill addr->un.dhcsrl = (d&017) | IENAB; 43513Sbill if ((tp->t_state&TTSTOP)==0) 43613Sbill tp->t_state |= FLUSH; 437113Sbill addr->dhbcr = -1; 438113Sbill } 43913Sbill splx(s); 44013Sbill } 44113Sbill 442117Sbill int dhsilo = 16; 443*168Sbill /* 444*168Sbill * Silo control is fixed strategy 445*168Sbill * here, paralleling only option available 446*168Sbill * on DZ-11. 447*168Sbill */ 44813Sbill /*ARGSUSED*/ 449*168Sbill dhtimer() 45013Sbill { 451*168Sbill register d; 452117Sbill register struct device *addr; 453117Sbill 45413Sbill addr = DHADDR; d = 0; 45513Sbill do { 456117Sbill if (dhact & (1<<d)) { 457117Sbill addr->dhsilo = dhsilo; 458117Sbill dhrint(d); 459117Sbill } 460117Sbill d++; 46113Sbill addr++; 46213Sbill } while (d < (NDH11+15)/16); 46313Sbill } 464