1*2421Skre /* dh.c 4.14 81/02/15 */ 213Sbill 31934Swnj #include "dh.h" 41561Sbill #if NDH11 > 0 513Sbill /* 61561Sbill * DH-11 driver 71561Sbill * 8*2421Skre * 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 242395Swnj /* This is to block the clock because we are using the silos */ 252395Swnj /* SHOULD RATHER QUEUE SOFTWARE INTERRUPT AT CLOCK TIME */ 26144Sbill #define spl5 spl6 27144Sbill 282395Swnj #define UBACVT(x,uban) (cbase[uban] + (short)((x)-(char *)cfree)) 2913Sbill 302395Swnj int dhcntrlr(), dhslave(), dhrint(), dhxint(); 312395Swnj struct uba_dinfo *dhinfo[NDH11]; 322395Swnj u_short dhstd[] = { 0 }; 332395Swnj struct uba_driver dhdriver = 34*2421Skre { dhcntrlr, dhslave, (int (*)())0, 0, 0, dhstd, "dh", dhinfo }; 352395Swnj 362395Swnj struct tty dh11[NDH11*16]; 37117Sbill int dhact; 38280Sbill int dhisilo; 392395Swnj int ndh11 = NDH11*16; 4013Sbill int dhstart(); 4113Sbill int ttrstrt(); 42*2421Skre int dh_ubinfo[MAXNUBA]; 43*2421Skre int cbase[MAXNUBA]; 4413Sbill 4513Sbill /* 4613Sbill * Hardware control bits 4713Sbill */ 4813Sbill #define BITS6 01 4913Sbill #define BITS7 02 5013Sbill #define BITS8 03 5113Sbill #define TWOSB 04 5213Sbill #define PENABLE 020 5313Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */ 5413Sbill #define OPAR 040 5513Sbill #define HDUPLX 040000 5613Sbill 57*2421Skre #define MAINT 01000 5813Sbill #define IENAB 030100 59105Sbill #define NXM 02000 60105Sbill #define CLRNXM 0400 6113Sbill #define PERROR 010000 6213Sbill #define FRERROR 020000 6313Sbill #define OVERRUN 040000 6413Sbill #define XINT 0100000 65*2421Skre #define RINT 0100 6613Sbill #define SSPEED 7 /* standard speed: 300 baud */ 6713Sbill 6813Sbill /* 6913Sbill * DM control bits 7013Sbill */ 7113Sbill #define TURNON 03 /* CD lead + line enable */ 7213Sbill #define TURNOFF 01 /* line enable */ 73168Sbill #define DTR 02 /* data terminal ready */ 7413Sbill #define RQS 04 /* request to send */ 7513Sbill 7613Sbill /* 7713Sbill * Software copy of last dhbar 7813Sbill */ 792395Swnj short dhsar[NDH11]; 8013Sbill 8113Sbill struct device 8213Sbill { 8313Sbill union { 8413Sbill short dhcsr; 8513Sbill char dhcsrl; 8613Sbill } un; 8713Sbill short dhnxch; 8813Sbill short dhlpr; 8913Sbill unsigned short dhcar; 9013Sbill short dhbcr; 9113Sbill unsigned short dhbar; 9213Sbill short dhbreak; 9313Sbill short dhsilo; 9413Sbill }; 9513Sbill 962395Swnj dhcntrlr(ui, reg) 972395Swnj struct uba_dinfo *ui; 982395Swnj caddr_t reg; 992395Swnj { 100*2421Skre struct device *dhaddr = (struct device *)reg; 101*2421Skre int i; 1022395Swnj 103*2421Skre dhaddr->un.dhcsr = IENAB; 104*2421Skre dhaddr->dhbcr = -1; 105*2421Skre dhaddr->dhbar = 1; 106*2421Skre dhaddr->dhcar = 0; 107*2421Skre for (i = 0; i < 1000000; i++) 108*2421Skre ; 109*2421Skre /* we should have had an interrupt */ 110*2421Skre dhaddr->un.dhcsr = 0; 111*2421Skre asm("cmpl r10,$0x200;beql 1f;subl2 $4,r10;1:;"); 1122395Swnj } 1132395Swnj 1142395Swnj dhslave(ui, reg, slaveno) 1152395Swnj struct uba_dinfo *ui; 1162395Swnj caddr_t reg; 1172395Swnj { 1182395Swnj 1192395Swnj /* could fill in local tables for the dh here */ 1202395Swnj } 1212395Swnj 12213Sbill /* 12313Sbill * Open a DH11 line. 12413Sbill */ 12513Sbill /*ARGSUSED*/ 12613Sbill dhopen(dev, flag) 1272395Swnj dev_t dev; 12813Sbill { 12913Sbill register struct tty *tp; 1302395Swnj register int unit, dh; 13113Sbill register struct device *addr; 1322395Swnj register struct uba_dinfo *ui; 13313Sbill int s; 13413Sbill 1352395Swnj unit = minor(dev); 1362395Swnj dh = unit >> 4; 1372395Swnj if (unit >= NDH11*16 || (ui = dhinfo[dh])->ui_alive == 0) { 13813Sbill u.u_error = ENXIO; 13913Sbill return; 14013Sbill } 1412395Swnj tp = &dh11[unit]; 1422395Swnj ui = dhinfo[dh]; 1432395Swnj addr = (struct device *)ui->ui_addr; 14413Sbill tp->t_addr = (caddr_t)addr; 14513Sbill tp->t_oproc = dhstart; 14613Sbill tp->t_iproc = NULL; 14713Sbill tp->t_state |= WOPEN; 14813Sbill s = spl6(); 149*2421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 150717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1512395Swnj dh_ubinfo[ui->ui_ubanum] = 152*2421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 1532395Swnj 512+NCLIST*sizeof(struct cblock), 0); 1542395Swnj cbase[ui->ui_ubanum] = (short)dh_ubinfo[ui->ui_ubanum]; 15513Sbill } 15613Sbill splx(s); 15713Sbill addr->un.dhcsr |= IENAB; 1582395Swnj dhact |= (1<<dh); 15913Sbill if ((tp->t_state&ISOPEN) == 0) { 16013Sbill ttychars(tp); 161168Sbill if (tp->t_ispeed == 0) { 162168Sbill tp->t_ispeed = SSPEED; 163168Sbill tp->t_ospeed = SSPEED; 164168Sbill tp->t_flags = ODDP|EVENP|ECHO; 165168Sbill } 1662395Swnj dhparam(unit); 16713Sbill } 16813Sbill if (tp->t_state&XCLUDE && u.u_uid!=0) { 16913Sbill u.u_error = EBUSY; 17013Sbill return; 17113Sbill } 17213Sbill dmopen(dev); 1732395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 17413Sbill } 17513Sbill 17613Sbill /* 17713Sbill * Close a DH11 line. 17813Sbill */ 17913Sbill /*ARGSUSED*/ 18013Sbill dhclose(dev, flag) 1812395Swnj dev_t dev; 1822395Swnj int flag; 18313Sbill { 18413Sbill register struct tty *tp; 1852395Swnj register unit; 18613Sbill 1872395Swnj unit = minor(dev); 1882395Swnj tp = &dh11[unit]; 18913Sbill (*linesw[tp->t_line].l_close)(tp); 1902196Stoy /* 1912196Stoy * Turn of the break bit in case somebody did a TIOCSBRK without 1922196Stoy * a TIOCCBRK. 1932196Stoy */ 1942395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 19513Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 1962395Swnj dmctl(unit, TURNOFF, DMSET); 19713Sbill ttyclose(tp); 19813Sbill } 19913Sbill 20013Sbill /* 20113Sbill * Read from a DH11 line. 20213Sbill */ 20313Sbill dhread(dev) 2042395Swnj dev_t dev; 20513Sbill { 2062395Swnj register struct tty *tp; 20713Sbill 2082395Swnj tp = &dh11[minor(dev)]; 20913Sbill (*linesw[tp->t_line].l_read)(tp); 21013Sbill } 21113Sbill 21213Sbill /* 21313Sbill * write on a DH11 line 21413Sbill */ 21513Sbill dhwrite(dev) 2162395Swnj dev_t dev; 21713Sbill { 2182395Swnj register struct tty *tp; 21913Sbill 2202395Swnj tp = &dh11[minor(dev)]; 22113Sbill (*linesw[tp->t_line].l_write)(tp); 22213Sbill } 22313Sbill 22413Sbill /* 22513Sbill * DH11 receiver interrupt. 22613Sbill */ 2272395Swnj dhrint(dh) 2282395Swnj int dh; 22913Sbill { 23013Sbill register struct tty *tp; 2312395Swnj register c; 23213Sbill register struct device *addr; 233117Sbill register struct tty *tp0; 2342395Swnj register struct uba_dinfo *ui; 235139Sbill int s; 23613Sbill 237139Sbill s = spl6(); /* see comment in clock.c */ 2382395Swnj ui = dhinfo[dh]; 2392395Swnj addr = (struct device *)ui->ui_addr; 2402395Swnj tp0 = &dh11[dh*16]; 24113Sbill while ((c = addr->dhnxch) < 0) { /* char. present */ 242117Sbill tp = tp0 + ((c>>8)&017); 2432395Swnj if (tp >= &dh11[NDH11*16]) 24413Sbill continue; 24513Sbill if((tp->t_state&ISOPEN)==0) { 24613Sbill wakeup((caddr_t)tp); 24713Sbill continue; 24813Sbill } 24913Sbill if (c&PERROR) 25013Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 25113Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 25213Sbill continue; 25313Sbill if (c&OVERRUN) 25413Sbill printf("O"); 25513Sbill if (c&FRERROR) /* break */ 25613Sbill if (tp->t_flags&RAW) 25713Sbill c = 0; /* null (for getty) */ 25813Sbill else 259168Sbill #ifdef IIASA 260168Sbill continue; 261168Sbill #else 262184Sbill c = tun.t_intrc; 263168Sbill #endif 264139Sbill if (tp->t_line == NETLDISC) { 265117Sbill c &= 0177; 266168Sbill BKINPUT(c, tp); 267117Sbill } else 268117Sbill (*linesw[tp->t_line].l_rint)(c,tp); 26913Sbill } 270139Sbill splx(s); 27113Sbill } 27213Sbill 27313Sbill /* 27413Sbill * stty/gtty for DH11 27513Sbill */ 27613Sbill /*ARGSUSED*/ 27713Sbill dhioctl(dev, cmd, addr, flag) 2782395Swnj caddr_t addr; 27913Sbill { 28013Sbill register struct tty *tp; 2812395Swnj register unit = minor(dev); 28213Sbill 2832395Swnj tp = &dh11[unit]; 284113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 285113Sbill if (cmd==0) 286113Sbill return; 2871895Swnj if (ttioctl(tp, cmd, addr, flag)) { 28813Sbill if (cmd==TIOCSETP||cmd==TIOCSETN) 2892395Swnj dhparam(unit); 290168Sbill } else switch(cmd) { 291168Sbill case TIOCSBRK: 2922395Swnj ((struct device *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 293168Sbill break; 294168Sbill case TIOCCBRK: 2952395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 296168Sbill break; 297168Sbill case TIOCSDTR: 2982395Swnj dmctl(unit, DTR|RQS, DMBIS); 299168Sbill break; 300168Sbill case TIOCCDTR: 3012395Swnj dmctl(unit, DTR|RQS, DMBIC); 302168Sbill break; 303168Sbill default: 30413Sbill u.u_error = ENOTTY; 305168Sbill } 30613Sbill } 30713Sbill 30813Sbill /* 30913Sbill * Set parameters from open or stty into the DH hardware 31013Sbill * registers. 31113Sbill */ 3122395Swnj dhparam(unit) 3132395Swnj register int unit; 31413Sbill { 31513Sbill register struct tty *tp; 31613Sbill register struct device *addr; 3172395Swnj register int lpar; 318300Sbill int s; 31913Sbill 3202395Swnj tp = &dh11[unit]; 32113Sbill addr = (struct device *)tp->t_addr; 322300Sbill s = spl5(); 3232395Swnj addr->un.dhcsrl = (unit&017) | IENAB; 32413Sbill /* 32513Sbill * Hang up line? 32613Sbill */ 32713Sbill if ((tp->t_ispeed)==0) { 32813Sbill tp->t_state |= HUPCLS; 3292395Swnj dmctl(unit, TURNOFF, DMSET); 33013Sbill return; 33113Sbill } 3322395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 33313Sbill if ((tp->t_ispeed) == 4) /* 134.5 baud */ 3342395Swnj lpar |= BITS6|PENABLE|HDUPLX; 3352312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 3362395Swnj lpar |= BITS8; 33713Sbill else 3382395Swnj lpar |= BITS7|PENABLE; 33913Sbill if ((tp->t_flags&EVENP) == 0) 3402395Swnj lpar |= OPAR; 34113Sbill if ((tp->t_ospeed) == 3) /* 110 baud */ 3422395Swnj lpar |= TWOSB; 3432395Swnj addr->dhlpr = lpar; 344300Sbill splx(s); 34513Sbill } 34613Sbill 34713Sbill /* 34813Sbill * DH11 transmitter interrupt. 34913Sbill * Restart each line which used to be active but has 35013Sbill * terminated transmission since the last interrupt. 35113Sbill */ 3522395Swnj dhxint(dh) 3532395Swnj int dh; 35413Sbill { 35513Sbill register struct tty *tp; 35613Sbill register struct device *addr; 35713Sbill short ttybit, bar, *sbar; 3582395Swnj register struct uba_dinfo *ui; 3592395Swnj register unit; 360144Sbill int s; 36113Sbill 362144Sbill s = spl6(); /* block the clock */ 3632395Swnj ui = dhinfo[dh]; 3642395Swnj addr = (struct device *)ui->ui_addr; 36513Sbill addr->un.dhcsr &= (short)~XINT; 366105Sbill if (addr->un.dhcsr & NXM) { 367*2421Skre asm("halt"); 368105Sbill addr->un.dhcsr |= CLRNXM; 369105Sbill printf("dh clr NXM\n"); 370105Sbill } 3712395Swnj sbar = &dhsar[dh]; 37213Sbill bar = *sbar & ~addr->dhbar; 3732395Swnj unit = dh * 16; ttybit = 1; 3742395Swnj for(; bar; unit++, ttybit <<= 1) { 37513Sbill if(bar&ttybit) { 37613Sbill *sbar &= ~ttybit; 37713Sbill bar &= ~ttybit; 3782395Swnj tp = &dh11[unit]; 379113Sbill tp->t_state &= ~BUSY; 380113Sbill if (tp->t_state&FLUSH) 381113Sbill tp->t_state &= ~FLUSH; 382113Sbill else { 3832395Swnj addr->un.dhcsrl = (unit&017)|IENAB; 384219Sbill ndflush(&tp->t_outq, 3852395Swnj (int)(short)addr->dhcar- 3862395Swnj UBACVT(tp->t_outq.c_cf,ui->ui_ubanum)); 387113Sbill } 388113Sbill if (tp->t_line) 38913Sbill (*linesw[tp->t_line].l_start)(tp); 390113Sbill else 39113Sbill dhstart(tp); 39213Sbill } 39313Sbill } 394144Sbill splx(s); 39513Sbill } 39613Sbill 39713Sbill /* 39813Sbill * Start (restart) transmission on the given DH11 line. 39913Sbill */ 40013Sbill dhstart(tp) 4012395Swnj register struct tty *tp; 40213Sbill { 40313Sbill register struct device *addr; 4042395Swnj register int nch, dh, unit; 4052395Swnj int s; 40613Sbill 40713Sbill /* 40813Sbill * If it's currently active, or delaying, 40913Sbill * no need to do anything. 41013Sbill */ 41113Sbill s = spl5(); 4122395Swnj unit = minor(tp->t_dev); 4132395Swnj dh = unit >> 4; 41413Sbill addr = (struct device *)tp->t_addr; 41513Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 41613Sbill goto out; 4172395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 41813Sbill tp->t_state &= ~ASLEEP; 41913Sbill if (tp->t_chan) 420168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 421168Sbill else 42213Sbill wakeup((caddr_t)&tp->t_outq); 42313Sbill } 42413Sbill if (tp->t_outq.c_cc == 0) 42513Sbill goto out; 4262395Swnj if (tp->t_flags & RAW) 42713Sbill nch = ndqb(&tp->t_outq, 0); 4282395Swnj else { 42913Sbill nch = ndqb(&tp->t_outq, 0200); 43013Sbill if (nch == 0) { 43113Sbill nch = getc(&tp->t_outq); 43213Sbill timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); 43313Sbill tp->t_state |= TIMEOUT; 43413Sbill goto out; 43513Sbill } 43613Sbill } 43713Sbill if (nch) { 4382395Swnj addr->un.dhcsrl = (unit&017)|IENAB; 4392395Swnj addr->dhcar = UBACVT(tp->t_outq.c_cf, 4402395Swnj dhinfo[dh]->ui_ubanum); 44113Sbill addr->dhbcr = -nch; 4422395Swnj nch = 1<<(unit&017); 44313Sbill addr->dhbar |= nch; 4442395Swnj dhsar[dh] |= nch; 44513Sbill tp->t_state |= BUSY; 44613Sbill } 4472395Swnj out: 44813Sbill splx(s); 44913Sbill } 45013Sbill 45113Sbill /* 45213Sbill * Stop output on a line. 45313Sbill * Assume call is made at spl6. 45413Sbill */ 45513Sbill /*ARGSUSED*/ 45613Sbill dhstop(tp, flag) 45713Sbill register struct tty *tp; 45813Sbill { 459113Sbill register struct device *addr; 4602395Swnj register int unit, s; 46113Sbill 462113Sbill addr = (struct device *)tp->t_addr; 46313Sbill s = spl6(); 464113Sbill if (tp->t_state & BUSY) { 4652395Swnj unit = minor(tp->t_dev); 4662395Swnj addr->un.dhcsrl = (unit&017) | IENAB; 46713Sbill if ((tp->t_state&TTSTOP)==0) 46813Sbill tp->t_state |= FLUSH; 469113Sbill addr->dhbcr = -1; 470113Sbill } 47113Sbill splx(s); 47213Sbill } 47313Sbill 474117Sbill int dhsilo = 16; 475168Sbill /* 476168Sbill * Silo control is fixed strategy 477168Sbill * here, paralleling only option available 478168Sbill * on DZ-11. 479168Sbill */ 48013Sbill /*ARGSUSED*/ 481168Sbill dhtimer() 48213Sbill { 4832395Swnj register int dh; 484117Sbill register struct device *addr; 4852395Swnj register struct uba_dinfo *ui; 486117Sbill 4872395Swnj dh = 0; 48813Sbill do { 4892395Swnj ui = dhinfo[dh]; 4902395Swnj addr = (struct device *)ui->ui_addr; 4912395Swnj if (dhact & (1<<dh)) { 4922395Swnj if ((dhisilo & (1<<dh)) == 0) { 493280Sbill addr->dhsilo = dhsilo; 4942395Swnj dhisilo |= 1<<dh; 495280Sbill } 4962395Swnj dhrint(dh); 497117Sbill } 4982395Swnj dh++; 4992395Swnj } while (dh < NDH11); 50013Sbill } 501280Sbill 502280Sbill /* 503280Sbill * Reset state of driver if UBA reset was necessary. 504280Sbill * Reset the csrl and lpr registers on open lines, and 505280Sbill * restart transmitters. 506280Sbill */ 5072395Swnj dhreset(uban) 508280Sbill { 5092395Swnj register int dh, unit; 510280Sbill register struct tty *tp; 5112395Swnj register struct uba_dinfo *ui; 512*2421Skre int i; 513280Sbill 514*2421Skre if (dh_ubinfo[uban] == 0) 515*2421Skre return; 516280Sbill printf(" dh"); 517*2421Skre ubarelse(uban, &dh_ubinfo[uban]); 518*2421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 519*2421Skre 512+NCLIST*sizeof (struct cblock), 0); 520*2421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 521*2421Skre dhisilo = 0; /* conservative */ 5222395Swnj dh = 0; 523*2421Skre for (dh = 0; dh < NDH11; dh++) { 524*2421Skre ui = dhinfo[dh]; 525*2421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 526*2421Skre continue; 527*2421Skre ((struct device *)ui->ui_addr)->un.dhcsr |= IENAB; 528*2421Skre unit = dh * 16; 529*2421Skre for (i = 0; i < 16; i++) { 530*2421Skre tp = &dh11[unit]; 531*2421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 532*2421Skre dhparam(unit); 533*2421Skre dmctl(unit, TURNON, DMSET); 534*2421Skre tp->t_state &= ~BUSY; 535*2421Skre dhstart(tp); 536*2421Skre } 537*2421Skre unit++; 538300Sbill } 539300Sbill } 540300Sbill dhtimer(); 541280Sbill } 5422395Swnj 5432395Swnj #if DHDM 5441944Swnj #include "../dev/dhdm.c" 5451944Swnj #else 5461944Swnj #include "../dev/dhfdm.c" 5471808Sbill #endif 5481944Swnj #endif 549