1*2456Swnj /* dh.c 4.15 81/02/16 */ 213Sbill 31934Swnj #include "dh.h" 41561Sbill #if NDH11 > 0 5*2456Swnj #define DELAY(i) { register int j = i; while (--j > 0); } 613Sbill /* 71561Sbill * DH-11 driver 82421Skre * DOESNT HANDLE EXTENDED ADDRESS BITS. 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" 182395Swnj #include "../h/buf.h" 1913Sbill #include "../h/uba.h" 20113Sbill #include "../h/bk.h" 211561Sbill #include "../h/clist.h" 221786Sbill #include "../h/mx.h" 2313Sbill 24*2456Swnj #define UBACVT(x,uban) (cbase[uban] + ((x)-(char *)cfree)) 25144Sbill 262395Swnj int dhcntrlr(), dhslave(), dhrint(), dhxint(); 272395Swnj struct uba_dinfo *dhinfo[NDH11]; 282395Swnj u_short dhstd[] = { 0 }; 292395Swnj struct uba_driver dhdriver = 30*2456Swnj { dhcntrlr, dhslave, 0, 0, dhstd, "dh", dhinfo }; 312395Swnj 322395Swnj struct tty dh11[NDH11*16]; 33117Sbill int dhact; 342395Swnj int ndh11 = NDH11*16; 3513Sbill int dhstart(); 3613Sbill int ttrstrt(); 372421Skre int dh_ubinfo[MAXNUBA]; 382421Skre int cbase[MAXNUBA]; 3913Sbill 4013Sbill /* 4113Sbill * Hardware control bits 4213Sbill */ 4313Sbill #define BITS6 01 4413Sbill #define BITS7 02 4513Sbill #define BITS8 03 4613Sbill #define TWOSB 04 4713Sbill #define PENABLE 020 4813Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 4913Sbill #define OPAR 040 5013Sbill #define HDUPLX 040000 5113Sbill 52*2456Swnj /* Bits in dhcsr */ 53*2456Swnj #define DH_TI 0100000 /* transmit interrupt */ 54*2456Swnj #define DH_SI 0040000 /* storage interrupt */ 55*2456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 56*2456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 57*2456Swnj #define DH_MC 0004000 /* master clear */ 58*2456Swnj #define DH_NXM 0002000 /* non-existant memory */ 59*2456Swnj #define DH_MM 0001000 /* maintenance mode */ 60*2456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 61*2456Swnj #define DH_RI 0000200 /* receiver interrupt */ 62*2456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 6313Sbill 64*2456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 65*2456Swnj 66*2456Swnj /* Bits in dhrcr */ 67*2456Swnj #define DH_PE 010000 /* parity error */ 68*2456Swnj #define DH_FE 020000 /* framing error */ 69*2456Swnj #define DH_DO 040000 /* data overrun */ 70*2456Swnj 7113Sbill /* 7213Sbill * DM control bits 7313Sbill */ 74*2456Swnj #define DM_ON 03 /* CD lead + line enable */ 75*2456Swnj #define DM_OFF 01 /* line enable */ 76*2456Swnj #define DM_DTR 02 /* data terminal ready */ 77*2456Swnj #define DM_RQS 04 /* request to send */ 7813Sbill 7913Sbill /* 8013Sbill * Software copy of last dhbar 8113Sbill */ 822395Swnj short dhsar[NDH11]; 8313Sbill 8413Sbill struct device 8513Sbill { 8613Sbill union { 87*2456Swnj short dhcsr; /* control-status register */ 88*2456Swnj char dhcsrl; /* low byte for line select */ 8913Sbill } un; 90*2456Swnj short dhrcr; /* receive character register */ 91*2456Swnj short dhlpr; /* line parameter register */ 92*2456Swnj u_short dhcar; /* current address register */ 93*2456Swnj short dhbcr; /* byte count register */ 94*2456Swnj u_short dhbar; /* buffer active register */ 95*2456Swnj short dhbreak; /* break control register */ 96*2456Swnj short dhsilo; /* silo status register */ 9713Sbill }; 9813Sbill 99*2456Swnj /* 100*2456Swnj * Routine for configuration to force a dh to interrupt. 101*2456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 102*2456Swnj */ 1032395Swnj dhcntrlr(ui, reg) 1042395Swnj struct uba_dinfo *ui; 1052395Swnj caddr_t reg; 1062395Swnj { 107*2456Swnj register int br, cvec; 108*2456Swnj register struct device *dhaddr = (struct device *)reg; 1092421Skre int i; 1102395Swnj 111*2456Swnj dhaddr->un.dhcsr = DH_TIE; 112*2456Swnj DELAY(5); 113*2456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1142421Skre dhaddr->dhbcr = -1; 115*2456Swnj dhaddr->dhcar = 0; 1162421Skre dhaddr->dhbar = 1; 117*2456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1182421Skre dhaddr->un.dhcsr = 0; 119*2456Swnj if (cvec && cvec != 0x200) 120*2456Swnj cvec -= 4; /* transmit -> receive */ 121*2456Swnj return (1); 1222395Swnj } 1232395Swnj 124*2456Swnj /* 125*2456Swnj * Routine called to init slave tables. 126*2456Swnj */ 1272395Swnj dhslave(ui, reg, slaveno) 1282395Swnj struct uba_dinfo *ui; 1292395Swnj caddr_t reg; 1302395Swnj { 1312395Swnj 132*2456Swnj /* no tables to set up */ 1332395Swnj } 1342395Swnj 13513Sbill /* 13613Sbill * Open a DH11 line. 13713Sbill */ 13813Sbill /*ARGSUSED*/ 13913Sbill dhopen(dev, flag) 1402395Swnj dev_t dev; 14113Sbill { 14213Sbill register struct tty *tp; 1432395Swnj register int unit, dh; 14413Sbill register struct device *addr; 1452395Swnj register struct uba_dinfo *ui; 14613Sbill int s; 14713Sbill 1482395Swnj unit = minor(dev); 1492395Swnj dh = unit >> 4; 1502395Swnj if (unit >= NDH11*16 || (ui = dhinfo[dh])->ui_alive == 0) { 15113Sbill u.u_error = ENXIO; 15213Sbill return; 15313Sbill } 1542395Swnj tp = &dh11[unit]; 1552395Swnj ui = dhinfo[dh]; 1562395Swnj addr = (struct device *)ui->ui_addr; 15713Sbill tp->t_addr = (caddr_t)addr; 15813Sbill tp->t_oproc = dhstart; 15913Sbill tp->t_iproc = NULL; 16013Sbill tp->t_state |= WOPEN; 16113Sbill s = spl6(); 1622421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 163717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1642395Swnj dh_ubinfo[ui->ui_ubanum] = 1652421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 1662395Swnj 512+NCLIST*sizeof(struct cblock), 0); 167*2456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 16813Sbill } 169*2456Swnj if ((dhact&(1<<dh)) == 0) { 170*2456Swnj addr->un.dhcsr |= DH_IE; 171*2456Swnj addr->dhsilo = 16; 172*2456Swnj dhact |= (1<<dh); 173*2456Swnj } 17413Sbill splx(s); 17513Sbill if ((tp->t_state&ISOPEN) == 0) { 17613Sbill ttychars(tp); 177168Sbill if (tp->t_ispeed == 0) { 178*2456Swnj tp->t_ispeed = B300; 179*2456Swnj tp->t_ospeed = B300; 180168Sbill tp->t_flags = ODDP|EVENP|ECHO; 181168Sbill } 1822395Swnj dhparam(unit); 18313Sbill } 18413Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 18513Sbill u.u_error = EBUSY; 18613Sbill return; 18713Sbill } 18813Sbill dmopen(dev); 1892395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 19013Sbill } 19113Sbill 19213Sbill /* 19313Sbill * Close a DH11 line. 19413Sbill */ 19513Sbill /*ARGSUSED*/ 19613Sbill dhclose(dev, flag) 1972395Swnj dev_t dev; 1982395Swnj int flag; 19913Sbill { 20013Sbill register struct tty *tp; 2012395Swnj register unit; 20213Sbill 2032395Swnj unit = minor(dev); 2042395Swnj tp = &dh11[unit]; 20513Sbill (*linesw[tp->t_line].l_close)(tp); 2062395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 20713Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 208*2456Swnj dmctl(unit, DM_OFF, DMSET); 20913Sbill ttyclose(tp); 21013Sbill } 21113Sbill 21213Sbill /* 21313Sbill * Read from a DH11 line. 21413Sbill */ 21513Sbill dhread(dev) 2162395Swnj dev_t dev; 21713Sbill { 2182395Swnj register struct tty *tp; 21913Sbill 2202395Swnj tp = &dh11[minor(dev)]; 22113Sbill (*linesw[tp->t_line].l_read)(tp); 22213Sbill } 22313Sbill 22413Sbill /* 22513Sbill * write on a DH11 line 22613Sbill */ 22713Sbill dhwrite(dev) 2282395Swnj dev_t dev; 22913Sbill { 2302395Swnj register struct tty *tp; 23113Sbill 2322395Swnj tp = &dh11[minor(dev)]; 23313Sbill (*linesw[tp->t_line].l_write)(tp); 23413Sbill } 23513Sbill 23613Sbill /* 23713Sbill * DH11 receiver interrupt. 23813Sbill */ 2392395Swnj dhrint(dh) 2402395Swnj int dh; 24113Sbill { 24213Sbill register struct tty *tp; 2432395Swnj register c; 24413Sbill register struct device *addr; 245117Sbill register struct tty *tp0; 2462395Swnj register struct uba_dinfo *ui; 247139Sbill int s; 24813Sbill 2492395Swnj ui = dhinfo[dh]; 250*2456Swnj if (ui == 0) { 251*2456Swnj printf("stray dhrint %d\n", dh); 252*2456Swnj asm("halt"); 253*2456Swnj return; 254*2456Swnj } 2552395Swnj addr = (struct device *)ui->ui_addr; 2562395Swnj tp0 = &dh11[dh*16]; 257*2456Swnj while ((c = addr->dhrcr) < 0) { /* char. present */ 258117Sbill tp = tp0 + ((c>>8)&017); 2592395Swnj if (tp >= &dh11[NDH11*16]) 26013Sbill continue; 26113Sbill if((tp->t_state&ISOPEN)==0) { 26213Sbill wakeup((caddr_t)tp); 26313Sbill continue; 26413Sbill } 265*2456Swnj if (c&DH_PE) 26613Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 26713Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 26813Sbill continue; 269*2456Swnj if (c&DH_DO) 27013Sbill printf("O"); 271*2456Swnj if (c&DH_FE) /* break */ 27213Sbill if (tp->t_flags&RAW) 27313Sbill c = 0; /* null (for getty) */ 27413Sbill else 275184Sbill c = tun.t_intrc; 276139Sbill if (tp->t_line == NETLDISC) { 277117Sbill c &= 0177; 278168Sbill BKINPUT(c, tp); 279117Sbill } else 280117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 28113Sbill } 28213Sbill } 28313Sbill 28413Sbill /* 28513Sbill * stty/gtty for DH11 28613Sbill */ 28713Sbill /*ARGSUSED*/ 28813Sbill dhioctl(dev, cmd, addr, flag) 2892395Swnj caddr_t addr; 29013Sbill { 29113Sbill register struct tty *tp; 2922395Swnj register unit = minor(dev); 29313Sbill 2942395Swnj tp = &dh11[unit]; 295113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 296113Sbill if (cmd==0) 297113Sbill return; 2981895Swnj if (ttioctl(tp, cmd, addr, flag)) { 29913Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 3002395Swnj dhparam(unit); 301168Sbill } else switch(cmd) { 302168Sbill case TIOCSBRK: 3032395Swnj ((struct device *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 304168Sbill break; 305168Sbill case TIOCCBRK: 3062395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 307168Sbill break; 308168Sbill case TIOCSDTR: 309*2456Swnj dmctl(unit, DM_DTR|DM_RQS, DMBIS); 310168Sbill break; 311168Sbill case TIOCCDTR: 312*2456Swnj dmctl(unit, DM_DTR|DM_RQS, DMBIC); 313168Sbill break; 314168Sbill default: 31513Sbill u.u_error = ENOTTY; 316168Sbill } 31713Sbill } 31813Sbill 31913Sbill /* 32013Sbill * Set parameters from open or stty into the DH hardware 32113Sbill * registers. 32213Sbill */ 3232395Swnj dhparam(unit) 3242395Swnj register int unit; 32513Sbill { 32613Sbill register struct tty *tp; 32713Sbill register struct device *addr; 3282395Swnj register int lpar; 329300Sbill int s; 33013Sbill 3312395Swnj tp = &dh11[unit]; 33213Sbill addr = (struct device *)tp->t_addr; 333300Sbill s = spl5(); 334*2456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 33513Sbill if ((tp->t_ispeed)==0) { 33613Sbill tp->t_state |= HUPCLS; 337*2456Swnj dmctl(unit, DM_OFF, DMSET); 33813Sbill return; 33913Sbill } 3402395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 34113Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 3422395Swnj lpar |= BITS6|PENABLE|HDUPLX; 3432312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 3442395Swnj lpar |= BITS8; 34513Sbill else 3462395Swnj lpar |= BITS7|PENABLE; 34713Sbill if ((tp->t_flags&EVENP) == 0) 3482395Swnj lpar |= OPAR; 34913Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 3502395Swnj lpar |= TWOSB; 3512395Swnj addr->dhlpr = lpar; 352300Sbill splx(s); 35313Sbill } 35413Sbill 35513Sbill /* 35613Sbill * DH11 transmitter interrupt. 35713Sbill * Restart each line which used to be active but has 35813Sbill * terminated transmission since the last interrupt. 35913Sbill */ 3602395Swnj dhxint(dh) 3612395Swnj int dh; 36213Sbill { 36313Sbill register struct tty *tp; 36413Sbill register struct device *addr; 36513Sbill short ttybit, bar, *sbar; 3662395Swnj register struct uba_dinfo *ui; 3672395Swnj register unit; 368144Sbill int s; 36913Sbill 3702395Swnj ui = dhinfo[dh]; 3712395Swnj addr = (struct device *)ui->ui_addr; 372*2456Swnj if (addr->un.dhcsr & DH_NXM) { 373*2456Swnj addr->un.dhcsr |= DH_CNI; 374*2456Swnj printf("dh%d NXM\n", ui->ui_ctlr); 375105Sbill } 376*2456Swnj addr->un.dhcsr &= (short)~DH_TI; 3772395Swnj sbar = &dhsar[dh]; 37813Sbill bar = *sbar & ~addr->dhbar; 3792395Swnj unit = dh * 16; ttybit = 1; 3802395Swnj for(; bar; unit++, ttybit <<= 1) { 38113Sbill if(bar&ttybit) { 38213Sbill *sbar &= ~ttybit; 38313Sbill bar &= ~ttybit; 3842395Swnj tp = &dh11[unit]; 385113Sbill tp->t_state &= ~BUSY; 386113Sbill if (tp->t_state&FLUSH) 387113Sbill tp->t_state &= ~FLUSH; 388113Sbill else { 389*2456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 390219Sbill ndflush(&tp->t_outq, 391*2456Swnj /* SHOULD PASTE ON 16&17 BITS HERE */ 392*2456Swnj addr->dhcar- 3932395Swnj UBACVT(tp->t_outq.c_cf,ui->ui_ubanum)); 394113Sbill } 395113Sbill if (tp->t_line) 39613Sbill (*linesw[tp->t_line].l_start)(tp); 397113Sbill else 39813Sbill dhstart(tp); 39913Sbill } 40013Sbill } 40113Sbill } 40213Sbill 40313Sbill /* 40413Sbill * Start (restart) transmission on the given DH11 line. 40513Sbill */ 40613Sbill dhstart(tp) 4072395Swnj register struct tty *tp; 40813Sbill { 40913Sbill register struct device *addr; 4102395Swnj register int nch, dh, unit; 4112395Swnj int s; 41213Sbill 41313Sbill /* 41413Sbill * If it's currently active, or delaying, 41513Sbill * no need to do anything. 41613Sbill */ 41713Sbill s = spl5(); 4182395Swnj unit = minor(tp->t_dev); 4192395Swnj dh = unit >> 4; 42013Sbill addr = (struct device *)tp->t_addr; 42113Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 42213Sbill goto out; 4232395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 42413Sbill tp->t_state &= ~ASLEEP; 42513Sbill if (tp->t_chan) 426168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 427168Sbill else 42813Sbill wakeup((caddr_t)&tp->t_outq); 42913Sbill } 43013Sbill if (tp->t_outq.c_cc == 0) 43113Sbill goto out; 4322395Swnj if (tp->t_flags & RAW) 43313Sbill nch = ndqb(&tp->t_outq, 0); 4342395Swnj else { 43513Sbill nch = ndqb(&tp->t_outq, 0200); 43613Sbill if (nch == 0) { 43713Sbill nch = getc(&tp->t_outq); 43813Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 43913Sbill tp->t_state |= TIMEOUT; 44013Sbill goto out; 44113Sbill } 44213Sbill } 44313Sbill if (nch) { 444*2456Swnj /* SHOULD PASTE ON BITS 16&17 HERE */ 445*2456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 4462395Swnj addr->dhcar = UBACVT(tp->t_outq.c_cf, 4472395Swnj dhinfo[dh]->ui_ubanum); 44813Sbill addr->dhbcr = -nch; 4492395Swnj nch = 1<<(unit&017); 45013Sbill addr->dhbar |= nch; 4512395Swnj dhsar[dh] |= nch; 45213Sbill tp->t_state |= BUSY; 45313Sbill } 4542395Swnj out: 45513Sbill splx(s); 45613Sbill } 45713Sbill 45813Sbill /* 45913Sbill * Stop output on a line. 46013Sbill */ 46113Sbill /*ARGSUSED*/ 46213Sbill dhstop(tp, flag) 46313Sbill register struct tty *tp; 46413Sbill { 465113Sbill register struct device *addr; 4662395Swnj register int unit, s; 46713Sbill 468113Sbill addr = (struct device *)tp->t_addr; 46913Sbill s = spl6(); 470113Sbill if (tp->t_state & BUSY) { 4712395Swnj unit = minor(tp->t_dev); 472*2456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 47313Sbill if ((tp->t_state&TTSTOP)==0) 47413Sbill tp->t_state |= FLUSH; 475113Sbill addr->dhbcr = -1; 476113Sbill } 47713Sbill splx(s); 47813Sbill } 47913Sbill 480168Sbill /* 481280Sbill * Reset state of driver if UBA reset was necessary. 482280Sbill * Reset the csrl and lpr registers on open lines, and 483280Sbill * restart transmitters. 484280Sbill */ 4852395Swnj dhreset(uban) 486280Sbill { 4872395Swnj register int dh, unit; 488280Sbill register struct tty *tp; 4892395Swnj register struct uba_dinfo *ui; 4902421Skre int i; 491280Sbill 4922421Skre if (dh_ubinfo[uban] == 0) 4932421Skre return; 494280Sbill printf(" dh"); 4952421Skre ubarelse(uban, &dh_ubinfo[uban]); 4962421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 4972421Skre 512+NCLIST*sizeof (struct cblock), 0); 4982421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 4992395Swnj dh = 0; 5002421Skre for (dh = 0; dh < NDH11; dh++) { 5012421Skre ui = dhinfo[dh]; 5022421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 5032421Skre continue; 504*2456Swnj ((struct device *)ui->ui_addr)->un.dhcsr |= DH_IE; 505*2456Swnj ((struct device *)ui->ui_addr)->dhsilo = 16; 5062421Skre unit = dh * 16; 5072421Skre for (i = 0; i < 16; i++) { 5082421Skre tp = &dh11[unit]; 5092421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 5102421Skre dhparam(unit); 511*2456Swnj dmctl(unit, DM_ON, DMSET); 5122421Skre tp->t_state &= ~BUSY; 5132421Skre dhstart(tp); 5142421Skre } 5152421Skre unit++; 516300Sbill } 517300Sbill } 518300Sbill dhtimer(); 519280Sbill } 5202395Swnj 521*2456Swnj dhtimer() 522*2456Swnj { 523*2456Swnj register int dh; 524*2456Swnj 525*2456Swnj for (dh = 0; dh < NDH11; dh++) 526*2456Swnj dhrint(dh); 527*2456Swnj } 528*2456Swnj 5292395Swnj #if DHDM 5301944Swnj #include "../dev/dhdm.c" 5311944Swnj #else 5321944Swnj #include "../dev/dhfdm.c" 5331808Sbill #endif 5341944Swnj #endif 535