1*2395Swnj /* dh.c 4.13 81/02/10 */ 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" 20*2395Swnj #include "../h/buf.h" 2113Sbill #include "../h/uba.h" 22113Sbill #include "../h/bk.h" 231561Sbill #include "../h/clist.h" 241786Sbill #include "../h/mx.h" 2513Sbill 26*2395Swnj /* This is to block the clock because we are using the silos */ 27*2395Swnj /* SHOULD RATHER QUEUE SOFTWARE INTERRUPT AT CLOCK TIME */ 28144Sbill #define spl5 spl6 29144Sbill 30*2395Swnj #define UBACVT(x,uban) (cbase[uban] + (short)((x)-(char *)cfree)) 3113Sbill 32*2395Swnj int dhcntrlr(), dhslave(), dhrint(), dhxint(); 33*2395Swnj struct uba_dinfo *dhinfo[NDH11]; 34*2395Swnj u_short dhstd[] = { 0 }; 35*2395Swnj int (*dhivec[])() = { dhrint, dhxint, 0 }; /* note: order matters */ 36*2395Swnj struct uba_driver dhdriver = 37*2395Swnj { dhcntrlr, dhslave, (int (*)())0, 0, 0, dhstd, dhinfo, dhivec }; 38*2395Swnj 39*2395Swnj struct tty dh11[NDH11*16]; 40117Sbill int dhact; 41280Sbill int dhisilo; 42*2395Swnj int ndh11 = NDH11*16; 4313Sbill int dhstart(); 4413Sbill int ttrstrt(); 45*2395Swnj int dh_ubinfo[4]; 46*2395Swnj int cbase[4]; 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 */ 80*2395Swnj short dhsar[NDH11]; 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 97*2395Swnj dhcntrlr(ui, reg) 98*2395Swnj struct uba_dinfo *ui; 99*2395Swnj caddr_t reg; 100*2395Swnj { 101*2395Swnj 102*2395Swnj ((struct device *)reg)->un.dhcsr |= IENABLE; 103*2395Swnj /* get it to interrupt */ 104*2395Swnj } 105*2395Swnj 106*2395Swnj dhslave(ui, reg, slaveno) 107*2395Swnj struct uba_dinfo *ui; 108*2395Swnj caddr_t reg; 109*2395Swnj { 110*2395Swnj 111*2395Swnj /* could fill in local tables for the dh here */ 112*2395Swnj } 113*2395Swnj 11413Sbill /* 11513Sbill * Open a DH11 line. 11613Sbill */ 11713Sbill /*ARGSUSED*/ 11813Sbill dhopen(dev, flag) 119*2395Swnj dev_t dev; 12013Sbill { 12113Sbill register struct tty *tp; 122*2395Swnj register int unit, dh; 12313Sbill register struct device *addr; 124*2395Swnj register struct uba_dinfo *ui; 12513Sbill int s; 12613Sbill 127*2395Swnj unit = minor(dev); 128*2395Swnj dh = unit >> 4; 129*2395Swnj if (unit >= NDH11*16 || (ui = dhinfo[dh])->ui_alive == 0) { 13013Sbill u.u_error = ENXIO; 13113Sbill return; 13213Sbill } 133*2395Swnj tp = &dh11[unit]; 134*2395Swnj ui = dhinfo[dh]; 135*2395Swnj addr = (struct device *)ui->ui_addr; 13613Sbill tp->t_addr = (caddr_t)addr; 13713Sbill tp->t_oproc = dhstart; 13813Sbill tp->t_iproc = NULL; 13913Sbill tp->t_state |= WOPEN; 14013Sbill s = spl6(); 141*2395Swnj if (dh_ubinfo[ui->ui_ubanum]) { 142717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 143*2395Swnj dh_ubinfo[ui->ui_ubanum] = 144*2395Swnj uballoc((caddr_t)cfree, 145*2395Swnj 512+NCLIST*sizeof(struct cblock), 0); 146*2395Swnj cbase[ui->ui_ubanum] = (short)dh_ubinfo[ui->ui_ubanum]; 14713Sbill } 14813Sbill splx(s); 14913Sbill addr->un.dhcsr |= IENAB; 150*2395Swnj dhact |= (1<<dh); 15113Sbill if ((tp->t_state&ISOPEN) == 0) { 15213Sbill ttychars(tp); 153168Sbill if (tp->t_ispeed == 0) { 154168Sbill tp->t_ispeed = SSPEED; 155168Sbill tp->t_ospeed = SSPEED; 156168Sbill tp->t_flags = ODDP|EVENP|ECHO; 157168Sbill } 158*2395Swnj dhparam(unit); 15913Sbill } 16013Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 16113Sbill u.u_error = EBUSY; 16213Sbill return; 16313Sbill } 16413Sbill dmopen(dev); 165*2395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 16613Sbill } 16713Sbill 16813Sbill /* 16913Sbill * Close a DH11 line. 17013Sbill */ 17113Sbill /*ARGSUSED*/ 17213Sbill dhclose(dev, flag) 173*2395Swnj dev_t dev; 174*2395Swnj int flag; 17513Sbill { 17613Sbill register struct tty *tp; 177*2395Swnj register unit; 17813Sbill 179*2395Swnj unit = minor(dev); 180*2395Swnj tp = &dh11[unit]; 18113Sbill (*linesw[tp->t_line].l_close)(tp); 1822196Stoy /* 1832196Stoy * Turn of the break bit in case somebody did a TIOCSBRK without 1842196Stoy * a TIOCCBRK. 1852196Stoy */ 186*2395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 18713Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 188*2395Swnj dmctl(unit, TURNOFF, DMSET); 18913Sbill ttyclose(tp); 19013Sbill } 19113Sbill 19213Sbill /* 19313Sbill * Read from a DH11 line. 19413Sbill */ 19513Sbill dhread(dev) 196*2395Swnj dev_t dev; 19713Sbill { 198*2395Swnj register struct tty *tp; 19913Sbill 200*2395Swnj tp = &dh11[minor(dev)]; 20113Sbill (*linesw[tp->t_line].l_read)(tp); 20213Sbill } 20313Sbill 20413Sbill /* 20513Sbill * write on a DH11 line 20613Sbill */ 20713Sbill dhwrite(dev) 208*2395Swnj dev_t dev; 20913Sbill { 210*2395Swnj register struct tty *tp; 21113Sbill 212*2395Swnj tp = &dh11[minor(dev)]; 21313Sbill (*linesw[tp->t_line].l_write)(tp); 21413Sbill } 21513Sbill 21613Sbill /* 21713Sbill * DH11 receiver interrupt. 21813Sbill */ 219*2395Swnj dhrint(dh) 220*2395Swnj int dh; 22113Sbill { 22213Sbill register struct tty *tp; 223*2395Swnj register c; 22413Sbill register struct device *addr; 225117Sbill register struct tty *tp0; 226*2395Swnj register struct uba_dinfo *ui; 227139Sbill int s; 22813Sbill 229139Sbill s = spl6(); /* see comment in clock.c */ 230*2395Swnj ui = dhinfo[dh]; 231*2395Swnj addr = (struct device *)ui->ui_addr; 232*2395Swnj tp0 = &dh11[dh*16]; 23313Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 234117Sbill tp = tp0 + ((c>>8)&017); 235*2395Swnj if (tp >= &dh11[NDH11*16]) 23613Sbill continue; 23713Sbill if((tp->t_state&ISOPEN)==0) { 23813Sbill wakeup((caddr_t)tp); 23913Sbill continue; 24013Sbill } 24113Sbill if (c&PERROR) 24213Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 24313Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 24413Sbill continue; 24513Sbill if (c&OVERRUN) 24613Sbill printf("O"); 24713Sbill if (c&FRERROR) /* break */ 24813Sbill if (tp->t_flags&RAW) 24913Sbill c = 0; /* null (for getty) */ 25013Sbill else 251168Sbill #ifdef IIASA 252168Sbill continue; 253168Sbill #else 254184Sbill c = tun.t_intrc; 255168Sbill #endif 256139Sbill if (tp->t_line == NETLDISC) { 257117Sbill c &= 0177; 258168Sbill BKINPUT(c, tp); 259117Sbill } else 260117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 26113Sbill } 262139Sbill splx(s); 26313Sbill } 26413Sbill 26513Sbill /* 26613Sbill * stty/gtty for DH11 26713Sbill */ 26813Sbill /*ARGSUSED*/ 26913Sbill dhioctl(dev, cmd, addr, flag) 270*2395Swnj caddr_t addr; 27113Sbill { 27213Sbill register struct tty *tp; 273*2395Swnj register unit = minor(dev); 27413Sbill 275*2395Swnj tp = &dh11[unit]; 276113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 277113Sbill if (cmd==0) 278113Sbill return; 2791895Swnj if (ttioctl(tp, cmd, addr, flag)) { 28013Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 281*2395Swnj dhparam(unit); 282168Sbill } else switch(cmd) { 283168Sbill case TIOCSBRK: 284*2395Swnj ((struct device *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 285168Sbill break; 286168Sbill case TIOCCBRK: 287*2395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 288168Sbill break; 289168Sbill case TIOCSDTR: 290*2395Swnj dmctl(unit, DTR|RQS, DMBIS); 291168Sbill break; 292168Sbill case TIOCCDTR: 293*2395Swnj dmctl(unit, DTR|RQS, DMBIC); 294168Sbill break; 295168Sbill default: 29613Sbill u.u_error = ENOTTY; 297168Sbill } 29813Sbill } 29913Sbill 30013Sbill /* 30113Sbill * Set parameters from open or stty into the DH hardware 30213Sbill * registers. 30313Sbill */ 304*2395Swnj dhparam(unit) 305*2395Swnj register int unit; 30613Sbill { 30713Sbill register struct tty *tp; 30813Sbill register struct device *addr; 309*2395Swnj register int lpar; 310300Sbill int s; 31113Sbill 312*2395Swnj tp = &dh11[unit]; 31313Sbill addr = (struct device *)tp->t_addr; 314300Sbill s = spl5(); 315*2395Swnj addr->un.dhcsrl = (unit&017) | IENAB; 31613Sbill /* 31713Sbill * Hang up line? 31813Sbill */ 31913Sbill if ((tp->t_ispeed)==0) { 32013Sbill tp->t_state |= HUPCLS; 321*2395Swnj dmctl(unit, TURNOFF, DMSET); 32213Sbill return; 32313Sbill } 324*2395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 32513Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 326*2395Swnj lpar |= BITS6|PENABLE|HDUPLX; 3272312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 328*2395Swnj lpar |= BITS8; 32913Sbill else 330*2395Swnj lpar |= BITS7|PENABLE; 33113Sbill if ((tp->t_flags&EVENP) == 0) 332*2395Swnj lpar |= OPAR; 33313Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 334*2395Swnj lpar |= TWOSB; 335*2395Swnj addr->dhlpr = lpar; 336300Sbill splx(s); 33713Sbill } 33813Sbill 33913Sbill /* 34013Sbill * DH11 transmitter interrupt. 34113Sbill * Restart each line which used to be active but has 34213Sbill * terminated transmission since the last interrupt. 34313Sbill */ 344*2395Swnj dhxint(dh) 345*2395Swnj int dh; 34613Sbill { 34713Sbill register struct tty *tp; 34813Sbill register struct device *addr; 34913Sbill short ttybit, bar, *sbar; 350*2395Swnj register struct uba_dinfo *ui; 351*2395Swnj register unit; 352144Sbill int s; 35313Sbill 354144Sbill s = spl6(); /* block the clock */ 355*2395Swnj ui = dhinfo[dh]; 356*2395Swnj addr = (struct device *)ui->ui_addr; 35713Sbill addr->un.dhcsr &= (short)~XINT; 358105Sbill if (addr->un.dhcsr & NXM) { 359105Sbill addr->un.dhcsr |= CLRNXM; 360105Sbill printf("dh clr NXM\n"); 361105Sbill } 362*2395Swnj sbar = &dhsar[dh]; 36313Sbill bar = *sbar & ~addr->dhbar; 364*2395Swnj unit = dh * 16; ttybit = 1; 365*2395Swnj for(; bar; unit++, ttybit <<= 1) { 36613Sbill if(bar&ttybit) { 36713Sbill *sbar &= ~ttybit; 36813Sbill bar &= ~ttybit; 369*2395Swnj tp = &dh11[unit]; 370113Sbill tp->t_state &= ~BUSY; 371113Sbill if (tp->t_state&FLUSH) 372113Sbill tp->t_state &= ~FLUSH; 373113Sbill else { 374*2395Swnj addr->un.dhcsrl = (unit&017)|IENAB; 375219Sbill ndflush(&tp->t_outq, 376*2395Swnj (int)(short)addr->dhcar- 377*2395Swnj UBACVT(tp->t_outq.c_cf,ui->ui_ubanum)); 378113Sbill } 379113Sbill if (tp->t_line) 38013Sbill (*linesw[tp->t_line].l_start)(tp); 381113Sbill else 38213Sbill dhstart(tp); 38313Sbill } 38413Sbill } 385144Sbill splx(s); 38613Sbill } 38713Sbill 38813Sbill /* 38913Sbill * Start (restart) transmission on the given DH11 line. 39013Sbill */ 39113Sbill dhstart(tp) 392*2395Swnj register struct tty *tp; 39313Sbill { 39413Sbill register struct device *addr; 395*2395Swnj register int nch, dh, unit; 396*2395Swnj int s; 39713Sbill 39813Sbill /* 39913Sbill * If it's currently active, or delaying, 40013Sbill * no need to do anything. 40113Sbill */ 40213Sbill s = spl5(); 403*2395Swnj unit = minor(tp->t_dev); 404*2395Swnj dh = unit >> 4; 40513Sbill addr = (struct device *)tp->t_addr; 40613Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 40713Sbill goto out; 408*2395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 40913Sbill tp->t_state &= ~ASLEEP; 41013Sbill if (tp->t_chan) 411168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 412168Sbill else 41313Sbill wakeup((caddr_t)&tp->t_outq); 41413Sbill } 41513Sbill if (tp->t_outq.c_cc == 0) 41613Sbill goto out; 417*2395Swnj if (tp->t_flags & RAW) 41813Sbill nch = ndqb(&tp->t_outq, 0); 419*2395Swnj else { 42013Sbill nch = ndqb(&tp->t_outq, 0200); 42113Sbill if (nch == 0) { 42213Sbill nch = getc(&tp->t_outq); 42313Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 42413Sbill tp->t_state |= TIMEOUT; 42513Sbill goto out; 42613Sbill } 42713Sbill } 42813Sbill if (nch) { 429*2395Swnj addr->un.dhcsrl = (unit&017)|IENAB; 430*2395Swnj addr->dhcar = UBACVT(tp->t_outq.c_cf, 431*2395Swnj dhinfo[dh]->ui_ubanum); 43213Sbill addr->dhbcr = -nch; 433*2395Swnj nch = 1<<(unit&017); 43413Sbill addr->dhbar |= nch; 435*2395Swnj dhsar[dh] |= nch; 43613Sbill tp->t_state |= BUSY; 43713Sbill } 438*2395Swnj out: 43913Sbill splx(s); 44013Sbill } 44113Sbill 44213Sbill /* 44313Sbill * Stop output on a line. 44413Sbill * Assume call is made at spl6. 44513Sbill */ 44613Sbill /*ARGSUSED*/ 44713Sbill dhstop(tp, flag) 44813Sbill register struct tty *tp; 44913Sbill { 450113Sbill register struct device *addr; 451*2395Swnj register int unit, s; 45213Sbill 453113Sbill addr = (struct device *)tp->t_addr; 45413Sbill s = spl6(); 455113Sbill if (tp->t_state & BUSY) { 456*2395Swnj unit = minor(tp->t_dev); 457*2395Swnj addr->un.dhcsrl = (unit&017) | IENAB; 45813Sbill if ((tp->t_state&TTSTOP)==0) 45913Sbill tp->t_state |= FLUSH; 460113Sbill addr->dhbcr = -1; 461113Sbill } 46213Sbill splx(s); 46313Sbill } 46413Sbill 465117Sbill int dhsilo = 16; 466168Sbill /* 467168Sbill * Silo control is fixed strategy 468168Sbill * here, paralleling only option available 469168Sbill * on DZ-11. 470168Sbill */ 47113Sbill /*ARGSUSED*/ 472168Sbill dhtimer() 47313Sbill { 474*2395Swnj register int dh; 475117Sbill register struct device *addr; 476*2395Swnj register struct uba_dinfo *ui; 477117Sbill 478*2395Swnj dh = 0; 47913Sbill do { 480*2395Swnj ui = dhinfo[dh]; 481*2395Swnj addr = (struct device *)ui->ui_addr; 482*2395Swnj if (dhact & (1<<dh)) { 483*2395Swnj if ((dhisilo & (1<<dh)) == 0) { 484280Sbill addr->dhsilo = dhsilo; 485*2395Swnj dhisilo |= 1<<dh; 486280Sbill } 487*2395Swnj dhrint(dh); 488117Sbill } 489*2395Swnj dh++; 490*2395Swnj } while (dh < NDH11); 49113Sbill } 492280Sbill 493280Sbill /* 494280Sbill * Reset state of driver if UBA reset was necessary. 495280Sbill * Reset the csrl and lpr registers on open lines, and 496280Sbill * restart transmitters. 497280Sbill */ 498*2395Swnj dhreset(uban) 499280Sbill { 500*2395Swnj register int dh, unit; 501280Sbill register struct tty *tp; 502280Sbill register struct device *addr; 503*2395Swnj register struct uba_dinfo *ui; 504*2395Swnj int uba; 505280Sbill 506*2395Swnj /*** WE SHOULD LOOK TO SEE IF UBA BEING RESET IS INTERESTING ***/ 507*2395Swnj 508280Sbill printf(" dh"); 509280Sbill dhisilo = 0; 510*2395Swnj for (uba = 0; uba < numuba; uba++) 511*2395Swnj if (dh_ubinfo[uba]) { 512*2395Swnj ubarelse(uba, &dh_ubinfo[uba]); 513*2395Swnj dh_ubinfo[uba] = uballoc(uba, (caddr_t)cfree, 514*2395Swnj 512+NCLIST*sizeof (struct cblock), 0); 515*2395Swnj cbase[uba] = (short)dh_ubinfo; 516*2395Swnj } 517*2395Swnj dh = 0; 518280Sbill do { 519*2395Swnj if (dhact & (1<<dh)) 520*2395Swnj ((struct device *)dhinfo[dh]->ui_addr)->un.dhcsr |= 521*2395Swnj IENAB; 522*2395Swnj dh++; 523*2395Swnj } while (dh < NDH11); 524*2395Swnj for (unit = 0; unit < NDH11*16; unit++) { 525*2395Swnj tp = &dh11[unit]; 526300Sbill if (tp->t_state & (ISOPEN|WOPEN)) { 527*2395Swnj dhparam(unit); 528*2395Swnj dmctl(unit, TURNON, DMSET); 529300Sbill tp->t_state &= ~BUSY; 530300Sbill dhstart(tp); 531300Sbill } 532300Sbill } 533300Sbill dhtimer(); 534280Sbill } 535*2395Swnj 536*2395Swnj #if DHDM 5371944Swnj #include "../dev/dhdm.c" 5381944Swnj #else 5391944Swnj #include "../dev/dhfdm.c" 5401808Sbill #endif 5411944Swnj #endif 542