1*280Sbill /* dh.c 3.12 06/22/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)) 34*280Sbill #define NDH11 32 /* 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; 44*280Sbill int dhisilo; 4513Sbill int ndh11 = NDH11; 4613Sbill int dhstart(); 4713Sbill int ttrstrt(); 48*280Sbill int dh_ubinfo; 49*280Sbill int cbase; 50*280Sbill int getcbase; 51*280Sbill int dhinit; 5213Sbill extern struct cblock cfree[]; 5313Sbill 5413Sbill /* 5513Sbill * Hardware control bits 5613Sbill */ 5713Sbill #define BITS6 01 5813Sbill #define BITS7 02 5913Sbill #define BITS8 03 6013Sbill #define TWOSB 04 6113Sbill #define PENABLE 020 6213Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 6313Sbill #define OPAR 040 6413Sbill #define HDUPLX 040000 6513Sbill 6613Sbill #define IENAB 030100 67105Sbill #define NXM 02000 68105Sbill #define CLRNXM 0400 6913Sbill #define PERROR 010000 7013Sbill #define FRERROR 020000 7113Sbill #define OVERRUN 040000 7213Sbill #define XINT 0100000 7313Sbill #define SSPEED 7 /* standard speed: 300 baud */ 7413Sbill 7513Sbill /* 7613Sbill * DM control bits 7713Sbill */ 7813Sbill #define TURNON 03 /* CD lead + line enable */ 7913Sbill #define TURNOFF 01 /* line enable */ 80168Sbill #define DTR 02 /* data terminal ready */ 8113Sbill #define RQS 04 /* request to send */ 8213Sbill 8313Sbill /* 8413Sbill * Software copy of last dhbar 8513Sbill */ 8613Sbill short dhsar[(NDH11+15)/16]; 8713Sbill 8813Sbill struct device 8913Sbill { 9013Sbill union { 9113Sbill short dhcsr; 9213Sbill char dhcsrl; 9313Sbill } un; 9413Sbill short dhnxch; 9513Sbill short dhlpr; 9613Sbill unsigned short dhcar; 9713Sbill short dhbcr; 9813Sbill unsigned short dhbar; 9913Sbill short dhbreak; 10013Sbill short dhsilo; 10113Sbill }; 10213Sbill 10313Sbill /* 10413Sbill * Open a DH11 line. 10513Sbill */ 10613Sbill /*ARGSUSED*/ 10713Sbill dhopen(dev, flag) 10813Sbill { 10913Sbill register struct tty *tp; 11013Sbill register d; 11113Sbill register struct device *addr; 11213Sbill int s; 11313Sbill 11413Sbill d = minor(dev) & 0177; 11513Sbill if (d >= NDH11) { 11613Sbill u.u_error = ENXIO; 11713Sbill return; 11813Sbill } 11913Sbill tp = &dh11[d]; 12013Sbill addr = DHADDR; 12113Sbill addr += d>>4; 12213Sbill tp->t_addr = (caddr_t)addr; 12313Sbill tp->t_oproc = dhstart; 12413Sbill tp->t_iproc = NULL; 12513Sbill tp->t_state |= WOPEN; 12613Sbill s = spl6(); 127117Sbill if (!getcbase) { 128117Sbill getcbase++; 129*280Sbill dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0); 130*280Sbill cbase = (short)dh_ubinfo; 13113Sbill } 13213Sbill splx(s); 13313Sbill addr->un.dhcsr |= IENAB; 134117Sbill dhact |= (1<<(d>>4)); 13513Sbill if ((tp->t_state&ISOPEN) == 0) { 13613Sbill ttychars(tp); 137168Sbill if (tp->t_ispeed == 0) { 138168Sbill tp->t_ispeed = SSPEED; 139168Sbill tp->t_ospeed = SSPEED; 140168Sbill tp->t_flags = ODDP|EVENP|ECHO; 141168Sbill } 14213Sbill dhparam(d); 14313Sbill } 14413Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 14513Sbill u.u_error = EBUSY; 14613Sbill return; 14713Sbill } 14813Sbill dmopen(dev); 14913Sbill (*linesw[tp->t_line].l_open)(dev,tp); 15013Sbill } 15113Sbill 15213Sbill /* 15313Sbill * Close a DH11 line. 15413Sbill */ 15513Sbill /*ARGSUSED*/ 15613Sbill dhclose(dev, flag) 15713Sbill dev_t dev; 15813Sbill int flag; 15913Sbill { 16013Sbill register struct tty *tp; 16113Sbill register d; 16213Sbill 16313Sbill d = minor(dev) & 0177; 16413Sbill tp = &dh11[d]; 16513Sbill (*linesw[tp->t_line].l_close)(tp); 16613Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 167168Sbill dmctl(d, TURNOFF, DMSET); 16813Sbill ttyclose(tp); 16913Sbill } 17013Sbill 17113Sbill /* 17213Sbill * Read from a DH11 line. 17313Sbill */ 17413Sbill dhread(dev) 17513Sbill { 17613Sbill register struct tty *tp; 17713Sbill 17813Sbill tp = &dh11[minor(dev) & 0177]; 17913Sbill (*linesw[tp->t_line].l_read)(tp); 18013Sbill } 18113Sbill 18213Sbill /* 18313Sbill * write on a DH11 line 18413Sbill */ 18513Sbill dhwrite(dev) 18613Sbill { 18713Sbill register struct tty *tp; 18813Sbill 18913Sbill tp = &dh11[minor(dev) & 0177]; 19013Sbill (*linesw[tp->t_line].l_write)(tp); 19113Sbill } 19213Sbill 19313Sbill /* 19413Sbill * DH11 receiver interrupt. 19513Sbill */ 19613Sbill dhrint(dev) 19713Sbill { 19813Sbill register struct tty *tp; 19913Sbill register short c; 20013Sbill register struct device *addr; 201117Sbill register struct tty *tp0; 202139Sbill int s; 20313Sbill 204139Sbill s = spl6(); /* see comment in clock.c */ 20513Sbill addr = DHADDR; 20613Sbill addr += minor(dev) & 0177; 207117Sbill tp0 = &dh11[((minor(dev)&0177)<<4)]; 20813Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 209117Sbill tp = tp0 + ((c>>8)&017); 21013Sbill if (tp >= &dh11[NDH11]) 21113Sbill continue; 21213Sbill if((tp->t_state&ISOPEN)==0) { 21313Sbill wakeup((caddr_t)tp); 21413Sbill continue; 21513Sbill } 21613Sbill if (c&PERROR) 21713Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 21813Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 21913Sbill continue; 22013Sbill if (c&OVERRUN) 22113Sbill printf("O"); 22213Sbill if (c&FRERROR) /* break */ 22313Sbill if (tp->t_flags&RAW) 22413Sbill c = 0; /* null (for getty) */ 22513Sbill else 226168Sbill #ifdef IIASA 227168Sbill continue; 228168Sbill #else 229184Sbill c = tun.t_intrc; 230168Sbill #endif 231139Sbill if (tp->t_line == NETLDISC) { 232117Sbill c &= 0177; 233168Sbill BKINPUT(c, tp); 234117Sbill } else 235117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 23613Sbill } 237139Sbill splx(s); 23813Sbill } 23913Sbill 24013Sbill /* 24113Sbill * stty/gtty for DH11 24213Sbill */ 24313Sbill /*ARGSUSED*/ 24413Sbill dhioctl(dev, cmd, addr, flag) 24513Sbill caddr_t addr; 24613Sbill { 24713Sbill register struct tty *tp; 24813Sbill 24913Sbill tp = &dh11[minor(dev) & 0177]; 250113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 251113Sbill if (cmd==0) 252113Sbill return; 25313Sbill if (ttioccomm(cmd, tp, addr, dev)) { 25413Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 25513Sbill dhparam(dev); 256168Sbill } else switch(cmd) { 257168Sbill case TIOCSBRK: 258168Sbill ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017); 259168Sbill break; 260168Sbill case TIOCCBRK: 261168Sbill ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017)); 262168Sbill break; 263168Sbill case TIOCSDTR: 264168Sbill dmctl(minor(dev), DTR|RQS, DMBIS); 265168Sbill break; 266168Sbill case TIOCCDTR: 267168Sbill dmctl(minor(dev), DTR|RQS, DMBIC); 268168Sbill break; 269168Sbill default: 27013Sbill u.u_error = ENOTTY; 271168Sbill } 27213Sbill } 27313Sbill 27413Sbill /* 27513Sbill * Set parameters from open or stty into the DH hardware 27613Sbill * registers. 27713Sbill */ 27813Sbill dhparam(dev) 27913Sbill { 28013Sbill register struct tty *tp; 28113Sbill register struct device *addr; 28213Sbill register d; 28313Sbill 28413Sbill d = minor(dev) & 0177; 28513Sbill tp = &dh11[d]; 28613Sbill addr = (struct device *)tp->t_addr; 28713Sbill spl5(); 28813Sbill addr->un.dhcsrl = (d&017) | IENAB; 28913Sbill /* 29013Sbill * Hang up line? 29113Sbill */ 29213Sbill if ((tp->t_ispeed)==0) { 29313Sbill tp->t_state |= HUPCLS; 294168Sbill dmctl(d, TURNOFF, DMSET); 29513Sbill return; 29613Sbill } 29713Sbill d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 29813Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 29913Sbill d |= BITS6|PENABLE|HDUPLX; 30013Sbill else if (tp->t_flags&RAW) 30113Sbill d |= BITS8; 30213Sbill else 30313Sbill d |= BITS7|PENABLE; 30413Sbill if ((tp->t_flags&EVENP) == 0) 30513Sbill d |= OPAR; 30613Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 30713Sbill d |= TWOSB; 30813Sbill addr->dhlpr = d; 30913Sbill spl0(); 31013Sbill } 31113Sbill 31213Sbill /* 31313Sbill * DH11 transmitter interrupt. 31413Sbill * Restart each line which used to be active but has 31513Sbill * terminated transmission since the last interrupt. 31613Sbill */ 31713Sbill dhxint(dev) 31813Sbill { 31913Sbill register struct tty *tp; 32013Sbill register struct device *addr; 32113Sbill register d; 32213Sbill short ttybit, bar, *sbar; 323144Sbill int s; 32413Sbill 325144Sbill s = spl6(); /* block the clock */ 32613Sbill d = minor(dev) & 0177; 32713Sbill addr = DHADDR + d; 32813Sbill addr->un.dhcsr &= (short)~XINT; 329105Sbill if (addr->un.dhcsr & NXM) { 330105Sbill addr->un.dhcsr |= CLRNXM; 331105Sbill printf("dh clr NXM\n"); 332105Sbill } 33313Sbill sbar = &dhsar[d]; 33413Sbill bar = *sbar & ~addr->dhbar; 335*280Sbill if (dhinit) 336*280Sbill bar = ~0; 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; 349*280Sbill if (dhinit == 0) 350219Sbill ndflush(&tp->t_outq, 351219Sbill (int)addr->dhcar-UBACVT(tp->t_outq.c_cf)); 352113Sbill } 353113Sbill if (tp->t_line) 35413Sbill (*linesw[tp->t_line].l_start)(tp); 355113Sbill else 35613Sbill dhstart(tp); 35713Sbill } 35813Sbill } 359144Sbill splx(s); 36013Sbill } 36113Sbill 36213Sbill /* 36313Sbill * Start (restart) transmission on the given DH11 line. 36413Sbill */ 36513Sbill dhstart(tp) 36613Sbill register struct tty *tp; 36713Sbill { 36813Sbill register struct device *addr; 36913Sbill register short nch; 37013Sbill int s, d; 37113Sbill 37213Sbill /* 37313Sbill * If it's currently active, or delaying, 37413Sbill * no need to do anything. 37513Sbill */ 37613Sbill s = spl5(); 37713Sbill d = tp-dh11; 37813Sbill addr = (struct device *)tp->t_addr; 37913Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 38013Sbill goto out; 38113Sbill 38213Sbill /* 38313Sbill * If the writer was sleeping on output overflow, 38413Sbill * wake him when low tide is reached. 38513Sbill */ 38613Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) { 38713Sbill tp->t_state &= ~ASLEEP; 38813Sbill if (tp->t_chan) 389168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 390168Sbill else 39113Sbill wakeup((caddr_t)&tp->t_outq); 39213Sbill } 39313Sbill 39413Sbill if (tp->t_outq.c_cc == 0) 39513Sbill goto out; 39613Sbill 39713Sbill /* 39813Sbill * Find number of characters to transfer. 39913Sbill */ 40013Sbill if (tp->t_flags & RAW) { 40113Sbill nch = ndqb(&tp->t_outq, 0); 40213Sbill } else { 40313Sbill nch = ndqb(&tp->t_outq, 0200); 40413Sbill if (nch == 0) { 40513Sbill nch = getc(&tp->t_outq); 40613Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 40713Sbill tp->t_state |= TIMEOUT; 40813Sbill goto out; 40913Sbill } 41013Sbill } 41113Sbill /* 41213Sbill * If any characters were set up, start transmission; 41313Sbill */ 41413Sbill if (nch) { 41513Sbill addr->un.dhcsrl = (d&017)|IENAB; 41613Sbill addr->dhcar = UBACVT(tp->t_outq.c_cf); 41713Sbill addr->dhbcr = -nch; 41813Sbill nch = 1<<(d&017); 41913Sbill addr->dhbar |= nch; 42013Sbill dhsar[d>>4] |= nch; 42113Sbill tp->t_state |= BUSY; 42213Sbill } 42313Sbill out: 42413Sbill splx(s); 42513Sbill } 42613Sbill 42713Sbill /* 42813Sbill * Stop output on a line. 42913Sbill * Assume call is made at spl6. 43013Sbill */ 43113Sbill /*ARGSUSED*/ 43213Sbill dhstop(tp, flag) 43313Sbill register struct tty *tp; 43413Sbill { 435113Sbill register struct device *addr; 436113Sbill register d, s; 43713Sbill 438113Sbill addr = (struct device *)tp->t_addr; 43913Sbill s = spl6(); 440113Sbill if (tp->t_state & BUSY) { 441113Sbill d = minor(tp->t_dev); 442113Sbill addr->un.dhcsrl = (d&017) | IENAB; 44313Sbill if ((tp->t_state&TTSTOP)==0) 44413Sbill tp->t_state |= FLUSH; 445113Sbill addr->dhbcr = -1; 446113Sbill } 44713Sbill splx(s); 44813Sbill } 44913Sbill 450117Sbill int dhsilo = 16; 451168Sbill /* 452168Sbill * Silo control is fixed strategy 453168Sbill * here, paralleling only option available 454168Sbill * on DZ-11. 455168Sbill */ 45613Sbill /*ARGSUSED*/ 457168Sbill dhtimer() 45813Sbill { 459168Sbill register d; 460117Sbill register struct device *addr; 461117Sbill 46213Sbill addr = DHADDR; d = 0; 46313Sbill do { 464117Sbill if (dhact & (1<<d)) { 465*280Sbill if ((dhisilo & (1<<d)) == 0) { 466*280Sbill addr->dhsilo = dhsilo; 467*280Sbill dhisilo |= 1<<d; 468*280Sbill } 469117Sbill dhrint(d); 470117Sbill } 471117Sbill d++; 47213Sbill addr++; 47313Sbill } while (d < (NDH11+15)/16); 47413Sbill } 475*280Sbill 476*280Sbill /* 477*280Sbill * Reset state of driver if UBA reset was necessary. 478*280Sbill * Reset the csrl and lpr registers on open lines, and 479*280Sbill * restart transmitters. 480*280Sbill */ 481*280Sbill dhreset() 482*280Sbill { 483*280Sbill int d; 484*280Sbill register struct tty *tp; 485*280Sbill register struct device *addr; 486*280Sbill 487*280Sbill if (getcbase == 0) 488*280Sbill return; 489*280Sbill printf(" dh"); 490*280Sbill dhinit = 1; 491*280Sbill dhisilo = 0; 492*280Sbill ubafree(dh_ubinfo); 493*280Sbill dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0); 494*280Sbill cbase = (short)dh_ubinfo; 495*280Sbill for (d = 0; d < NDH11; d++) { 496*280Sbill tp = &dh11[d]; 497*280Sbill if (tp->t_state & (ISOPEN|WOPEN)) 498*280Sbill dhparam(d); 499*280Sbill } 500*280Sbill dhtimer(); 501*280Sbill d = 0; 502*280Sbill do { 503*280Sbill addr = DHADDR + d; 504*280Sbill addr->un.dhcsr |= IENAB; 505*280Sbill if (dhact & (1<<d)) 506*280Sbill dhxint(d<<4); 507*280Sbill d++; 508*280Sbill } while (d < (NDH11+15)/16); 509*280Sbill dhinit = 0; 510*280Sbill } 511