1*2468Swnj /* dh.c 4.16 81/02/17 */ 213Sbill 31934Swnj #include "dh.h" 41561Sbill #if NDH11 > 0 52456Swnj #define DELAY(i) { register int j = i; while (--j > 0); } 613Sbill /* 71561Sbill * DH-11 driver 813Sbill */ 913Sbill #include "../h/param.h" 1013Sbill #include "../h/conf.h" 1113Sbill #include "../h/dir.h" 1213Sbill #include "../h/user.h" 1313Sbill #include "../h/tty.h" 1413Sbill #include "../h/map.h" 1513Sbill #include "../h/pte.h" 162395Swnj #include "../h/buf.h" 1713Sbill #include "../h/uba.h" 18113Sbill #include "../h/bk.h" 191561Sbill #include "../h/clist.h" 201786Sbill #include "../h/mx.h" 21*2468Swnj #include "../h/file.h" 2213Sbill 23*2468Swnj #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 24144Sbill 25*2468Swnj /* 26*2468Swnj * Definition of the controller for the auto-configuration program. 27*2468Swnj */ 282395Swnj int dhcntrlr(), dhslave(), dhrint(), dhxint(); 292395Swnj struct uba_dinfo *dhinfo[NDH11]; 302395Swnj u_short dhstd[] = { 0 }; 312395Swnj struct uba_driver dhdriver = 322456Swnj { dhcntrlr, dhslave, 0, 0, dhstd, "dh", dhinfo }; 332395Swnj 342395Swnj struct tty dh11[NDH11*16]; 35117Sbill int dhact; 362395Swnj int ndh11 = NDH11*16; 3713Sbill int dhstart(); 3813Sbill int ttrstrt(); 392421Skre int dh_ubinfo[MAXNUBA]; 402421Skre int cbase[MAXNUBA]; 4113Sbill 42*2468Swnj /* Bits in dhlpr */ 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 522456Swnj /* Bits in dhcsr */ 532456Swnj #define DH_TI 0100000 /* transmit interrupt */ 542456Swnj #define DH_SI 0040000 /* storage interrupt */ 552456Swnj #define DH_TIE 0020000 /* transmit interrupt enable */ 562456Swnj #define DH_SIE 0010000 /* storage interrupt enable */ 572456Swnj #define DH_MC 0004000 /* master clear */ 582456Swnj #define DH_NXM 0002000 /* non-existant memory */ 592456Swnj #define DH_MM 0001000 /* maintenance mode */ 602456Swnj #define DH_CNI 0000400 /* clear non-existant memory interrupt */ 612456Swnj #define DH_RI 0000200 /* receiver interrupt */ 622456Swnj #define DH_RIE 0000100 /* receiver interrupt enable */ 6313Sbill 642456Swnj #define DH_IE (DH_TIE|DH_SIE|DH_RIE) 652456Swnj 662456Swnj /* Bits in dhrcr */ 672456Swnj #define DH_PE 010000 /* parity error */ 682456Swnj #define DH_FE 020000 /* framing error */ 692456Swnj #define DH_DO 040000 /* data overrun */ 702456Swnj 7113Sbill /* 7213Sbill * DM control bits 7313Sbill */ 742456Swnj #define DM_ON 03 /* CD lead + line enable */ 752456Swnj #define DM_OFF 01 /* line enable */ 762456Swnj #define DM_DTR 02 /* data terminal ready */ 772456Swnj #define DM_RQS 04 /* request to send */ 7813Sbill 79*2468Swnj /* Software copy of last dhbar */ 802395Swnj short dhsar[NDH11]; 8113Sbill 8213Sbill struct device 8313Sbill { 8413Sbill union { 852456Swnj short dhcsr; /* control-status register */ 862456Swnj char dhcsrl; /* low byte for line select */ 8713Sbill } un; 882456Swnj short dhrcr; /* receive character register */ 892456Swnj short dhlpr; /* line parameter register */ 902456Swnj u_short dhcar; /* current address register */ 912456Swnj short dhbcr; /* byte count register */ 922456Swnj u_short dhbar; /* buffer active register */ 932456Swnj short dhbreak; /* break control register */ 942456Swnj short dhsilo; /* silo status register */ 9513Sbill }; 9613Sbill 972456Swnj /* 982456Swnj * Routine for configuration to force a dh to interrupt. 992456Swnj * Set to transmit at 9600 baud, and cause a transmitter interrupt. 1002456Swnj */ 101*2468Swnj /*ARGSUSED*/ 1022395Swnj dhcntrlr(ui, reg) 1032395Swnj struct uba_dinfo *ui; 1042395Swnj caddr_t reg; 1052395Swnj { 106*2468Swnj register int br, cvec; /* these are ``value-result'' */ 1072456Swnj register struct device *dhaddr = (struct device *)reg; 1082421Skre int i; 1092395Swnj 1102456Swnj dhaddr->un.dhcsr = DH_TIE; 1112456Swnj DELAY(5); 1122456Swnj dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; 1132421Skre dhaddr->dhbcr = -1; 1142456Swnj dhaddr->dhcar = 0; 1152421Skre dhaddr->dhbar = 1; 1162456Swnj DELAY(100000); /* wait 1/10'th of a sec for interrupt */ 1172421Skre dhaddr->un.dhcsr = 0; 1182456Swnj if (cvec && cvec != 0x200) 1192456Swnj cvec -= 4; /* transmit -> receive */ 1202456Swnj return (1); 1212395Swnj } 1222395Swnj 1232456Swnj /* 1242456Swnj * Routine called to init slave tables. 1252456Swnj */ 1262395Swnj dhslave(ui, reg, slaveno) 1272395Swnj struct uba_dinfo *ui; 1282395Swnj caddr_t reg; 1292395Swnj { 1302395Swnj 1312456Swnj /* no tables to set up */ 1322395Swnj } 1332395Swnj 13413Sbill /* 135*2468Swnj * Open a DH11 line, mapping the clist onto the uba if this 136*2468Swnj * is the first dh on this uba. Turn on this dh if this is 137*2468Swnj * the first use of it. Also do a dmopen to wait for carrier. 13813Sbill */ 13913Sbill /*ARGSUSED*/ 14013Sbill dhopen(dev, flag) 1412395Swnj dev_t dev; 14213Sbill { 14313Sbill register struct tty *tp; 1442395Swnj register int unit, dh; 14513Sbill register struct device *addr; 1462395Swnj register struct uba_dinfo *ui; 14713Sbill int s; 14813Sbill 1492395Swnj unit = minor(dev); 1502395Swnj dh = unit >> 4; 151*2468Swnj if (unit >= NDH11*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { 15213Sbill u.u_error = ENXIO; 15313Sbill return; 15413Sbill } 1552395Swnj tp = &dh11[unit]; 156*2468Swnj if (tp->t_state&XCLUDE && u.u_uid!=0) { 157*2468Swnj u.u_error = EBUSY; 158*2468Swnj return; 159*2468Swnj } 1602395Swnj addr = (struct device *)ui->ui_addr; 16113Sbill tp->t_addr = (caddr_t)addr; 16213Sbill tp->t_oproc = dhstart; 16313Sbill tp->t_iproc = NULL; 16413Sbill tp->t_state |= WOPEN; 165*2468Swnj /* 166*2468Swnj * While setting up state for this uba and this dh, 167*2468Swnj * block uba resets which can clear the state. 168*2468Swnj */ 169*2468Swnj s = spl5(); 1702421Skre if (dh_ubinfo[ui->ui_ubanum] == 0) { 171717Sbill /* 512+ is a kludge to try to get around a hardware problem */ 1722395Swnj dh_ubinfo[ui->ui_ubanum] = 1732421Skre uballoc(ui->ui_ubanum, (caddr_t)cfree, 1742395Swnj 512+NCLIST*sizeof(struct cblock), 0); 1752456Swnj cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; 17613Sbill } 1772456Swnj if ((dhact&(1<<dh)) == 0) { 1782456Swnj addr->un.dhcsr |= DH_IE; 179*2468Swnj DELAY(5); 180*2468Swnj dhact |= (1<<dh); 1812456Swnj addr->dhsilo = 16; 1822456Swnj } 18313Sbill splx(s); 184*2468Swnj /* 185*2468Swnj * If this is first open, initialze tty state to default. 186*2468Swnj */ 18713Sbill if ((tp->t_state&ISOPEN) == 0) { 18813Sbill ttychars(tp); 189168Sbill if (tp->t_ispeed == 0) { 1902456Swnj tp->t_ispeed = B300; 1912456Swnj tp->t_ospeed = B300; 192168Sbill tp->t_flags = ODDP|EVENP|ECHO; 193168Sbill } 1942395Swnj dhparam(unit); 19513Sbill } 196*2468Swnj /* 197*2468Swnj * Wait for carrier, then process line discipline specific open. 198*2468Swnj */ 19913Sbill dmopen(dev); 2002395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 20113Sbill } 20213Sbill 20313Sbill /* 204*2468Swnj * Close a DH11 line, turning off the DM11. 20513Sbill */ 20613Sbill /*ARGSUSED*/ 20713Sbill dhclose(dev, flag) 2082395Swnj dev_t dev; 2092395Swnj int flag; 21013Sbill { 21113Sbill register struct tty *tp; 2122395Swnj register unit; 21313Sbill 2142395Swnj unit = minor(dev); 2152395Swnj tp = &dh11[unit]; 21613Sbill (*linesw[tp->t_line].l_close)(tp); 2172395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 21813Sbill if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) 2192456Swnj dmctl(unit, DM_OFF, DMSET); 22013Sbill ttyclose(tp); 22113Sbill } 22213Sbill 22313Sbill dhread(dev) 2242395Swnj dev_t dev; 22513Sbill { 2262395Swnj register struct tty *tp; 22713Sbill 2282395Swnj tp = &dh11[minor(dev)]; 22913Sbill (*linesw[tp->t_line].l_read)(tp); 23013Sbill } 23113Sbill 23213Sbill dhwrite(dev) 2332395Swnj dev_t dev; 23413Sbill { 2352395Swnj register struct tty *tp; 23613Sbill 2372395Swnj tp = &dh11[minor(dev)]; 23813Sbill (*linesw[tp->t_line].l_write)(tp); 23913Sbill } 24013Sbill 24113Sbill /* 24213Sbill * DH11 receiver interrupt. 24313Sbill */ 2442395Swnj dhrint(dh) 2452395Swnj int dh; 24613Sbill { 24713Sbill register struct tty *tp; 2482395Swnj register c; 24913Sbill register struct device *addr; 250117Sbill register struct tty *tp0; 2512395Swnj register struct uba_dinfo *ui; 252139Sbill int s; 25313Sbill 2542395Swnj ui = dhinfo[dh]; 2552395Swnj addr = (struct device *)ui->ui_addr; 256*2468Swnj tp0 = &dh11[dh<<4]; 257*2468Swnj /* 258*2468Swnj * Loop fetching characters from the silo for this 259*2468Swnj * dh until there are no more in the silo. 260*2468Swnj */ 261*2468Swnj while ((c = addr->dhrcr) < 0) { 262*2468Swnj tp = tp0 + ((c>>8)&0xf); 263*2468Swnj if ((tp->t_state&ISOPEN)==0) { 26413Sbill wakeup((caddr_t)tp); 26513Sbill continue; 26613Sbill } 267*2468Swnj if (c & DH_PE) 26813Sbill if ((tp->t_flags&(EVENP|ODDP))==EVENP 26913Sbill || (tp->t_flags&(EVENP|ODDP))==ODDP ) 27013Sbill continue; 271*2468Swnj if (c & DH_DO) 27213Sbill printf("O"); 273*2468Swnj if (c & DH_FE) 274*2468Swnj /* 275*2468Swnj * At framing error (break) generate 276*2468Swnj * a null (in raw mode, for getty), or a 277*2468Swnj * interrupt (in cooked/cbreak mode). 278*2468Swnj */ 27913Sbill if (tp->t_flags&RAW) 280*2468Swnj c = 0; 28113Sbill else 282184Sbill c = tun.t_intrc; 283139Sbill if (tp->t_line == NETLDISC) { 284117Sbill c &= 0177; 285168Sbill BKINPUT(c, tp); 286117Sbill } else 287*2468Swnj (*linesw[tp->t_line].l_rint)(c, tp); 28813Sbill } 28913Sbill } 29013Sbill 29113Sbill /* 292*2468Swnj * Ioctl for DH11. 29313Sbill */ 29413Sbill /*ARGSUSED*/ 29513Sbill dhioctl(dev, cmd, addr, flag) 2962395Swnj caddr_t addr; 29713Sbill { 29813Sbill register struct tty *tp; 2992395Swnj register unit = minor(dev); 30013Sbill 3012395Swnj tp = &dh11[unit]; 302113Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 303*2468Swnj if (cmd == 0) 304113Sbill return; 3051895Swnj if (ttioctl(tp, cmd, addr, flag)) { 306*2468Swnj if (cmd==TIOCSETP || cmd==TIOCSETN) 3072395Swnj dhparam(unit); 308168Sbill } else switch(cmd) { 309168Sbill case TIOCSBRK: 3102395Swnj ((struct device *)(tp->t_addr))->dhbreak |= 1<<(unit&017); 311168Sbill break; 312168Sbill case TIOCCBRK: 3132395Swnj ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 314168Sbill break; 315168Sbill case TIOCSDTR: 3162456Swnj dmctl(unit, DM_DTR|DM_RQS, DMBIS); 317168Sbill break; 318168Sbill case TIOCCDTR: 3192456Swnj dmctl(unit, DM_DTR|DM_RQS, DMBIC); 320168Sbill break; 321168Sbill default: 32213Sbill u.u_error = ENOTTY; 323168Sbill } 32413Sbill } 32513Sbill 32613Sbill /* 32713Sbill * Set parameters from open or stty into the DH hardware 32813Sbill * registers. 32913Sbill */ 3302395Swnj dhparam(unit) 3312395Swnj register int unit; 33213Sbill { 33313Sbill register struct tty *tp; 33413Sbill register struct device *addr; 3352395Swnj register int lpar; 336300Sbill int s; 33713Sbill 3382395Swnj tp = &dh11[unit]; 33913Sbill addr = (struct device *)tp->t_addr; 340*2468Swnj /* 341*2468Swnj * Block interrupts so parameters will be set 342*2468Swnj * before the line interrupts. 343*2468Swnj */ 344300Sbill s = spl5(); 345*2468Swnj addr->un.dhcsrl = (unit&0xf) | DH_IE; 34613Sbill if ((tp->t_ispeed)==0) { 34713Sbill tp->t_state |= HUPCLS; 3482456Swnj dmctl(unit, DM_OFF, DMSET); 34913Sbill return; 35013Sbill } 3512395Swnj lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 352*2468Swnj if ((tp->t_ispeed) == B134) 3532395Swnj lpar |= BITS6|PENABLE|HDUPLX; 3542312Skre else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) 3552395Swnj lpar |= BITS8; 35613Sbill else 3572395Swnj lpar |= BITS7|PENABLE; 35813Sbill if ((tp->t_flags&EVENP) == 0) 3592395Swnj lpar |= OPAR; 360*2468Swnj if ((tp->t_ospeed) == B110) 3612395Swnj lpar |= TWOSB; 3622395Swnj addr->dhlpr = lpar; 363300Sbill splx(s); 36413Sbill } 36513Sbill 36613Sbill /* 36713Sbill * DH11 transmitter interrupt. 36813Sbill * Restart each line which used to be active but has 36913Sbill * terminated transmission since the last interrupt. 37013Sbill */ 3712395Swnj dhxint(dh) 3722395Swnj int dh; 37313Sbill { 37413Sbill register struct tty *tp; 37513Sbill register struct device *addr; 37613Sbill short ttybit, bar, *sbar; 3772395Swnj register struct uba_dinfo *ui; 378*2468Swnj register int unit; 379144Sbill int s; 380*2468Swnj u_short cnt; 38113Sbill 3822395Swnj ui = dhinfo[dh]; 3832395Swnj addr = (struct device *)ui->ui_addr; 3842456Swnj if (addr->un.dhcsr & DH_NXM) { 385*2468Swnj DELAY(5); 3862456Swnj addr->un.dhcsr |= DH_CNI; 387*2468Swnj printf("dh%d NXM\n", dh); 388105Sbill } 3892395Swnj sbar = &dhsar[dh]; 39013Sbill bar = *sbar & ~addr->dhbar; 3912395Swnj unit = dh * 16; ttybit = 1; 392*2468Swnj addr->un.dhcsr &= (short)~DH_TI; 393*2468Swnj for (; bar; unit++, ttybit <<= 1) { 394*2468Swnj if (bar & ttybit) { 39513Sbill *sbar &= ~ttybit; 39613Sbill bar &= ~ttybit; 3972395Swnj tp = &dh11[unit]; 398113Sbill tp->t_state &= ~BUSY; 399113Sbill if (tp->t_state&FLUSH) 400113Sbill tp->t_state &= ~FLUSH; 401113Sbill else { 4022456Swnj addr->un.dhcsrl = (unit&017)|DH_IE; 403*2468Swnj DELAY(5); 404*2468Swnj /* 405*2468Swnj * Do arithmetic in a short to make up 406*2468Swnj * for lost 16&17 bits. 407*2468Swnj */ 408*2468Swnj cnt = addr->dhcar - 409*2468Swnj UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 410*2468Swnj ndflush(&tp->t_outq, cnt); 411113Sbill } 412113Sbill if (tp->t_line) 41313Sbill (*linesw[tp->t_line].l_start)(tp); 414113Sbill else 41513Sbill dhstart(tp); 41613Sbill } 41713Sbill } 41813Sbill } 41913Sbill 42013Sbill /* 42113Sbill * Start (restart) transmission on the given DH11 line. 42213Sbill */ 42313Sbill dhstart(tp) 4242395Swnj register struct tty *tp; 42513Sbill { 42613Sbill register struct device *addr; 427*2468Swnj register int car, dh, unit, nch; 4282395Swnj int s; 42913Sbill 430*2468Swnj unit = minor(tp->t_dev); 431*2468Swnj dh = unit >> 4; 432*2468Swnj unit &= 0xf; 433*2468Swnj addr = (struct device *)tp->t_addr; 434*2468Swnj 43513Sbill /* 436*2468Swnj * Must hold interrupts in following code to prevent 437*2468Swnj * state of the tp from changing. 43813Sbill */ 43913Sbill s = spl5(); 440*2468Swnj /* 441*2468Swnj * If it's currently active, or delaying, no need to do anything. 442*2468Swnj */ 44313Sbill if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) 44413Sbill goto out; 445*2468Swnj /* 446*2468Swnj * If there are sleepers, and output has drained below low 447*2468Swnj * water mark, wake up the sleepers. 448*2468Swnj */ 4492395Swnj if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { 45013Sbill tp->t_state &= ~ASLEEP; 45113Sbill if (tp->t_chan) 452168Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 453168Sbill else 45413Sbill wakeup((caddr_t)&tp->t_outq); 45513Sbill } 456*2468Swnj /* 457*2468Swnj * Now restart transmission unless the output queue is 458*2468Swnj * empty. 459*2468Swnj */ 46013Sbill if (tp->t_outq.c_cc == 0) 46113Sbill goto out; 4622395Swnj if (tp->t_flags & RAW) 46313Sbill nch = ndqb(&tp->t_outq, 0); 4642395Swnj else { 46513Sbill nch = ndqb(&tp->t_outq, 0200); 466*2468Swnj /* 467*2468Swnj * If first thing on queue is a delay process it. 468*2468Swnj */ 46913Sbill if (nch == 0) { 47013Sbill nch = getc(&tp->t_outq); 471*2468Swnj timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 47213Sbill tp->t_state |= TIMEOUT; 47313Sbill goto out; 47413Sbill } 47513Sbill } 476*2468Swnj /* 477*2468Swnj * If characters to transmit, restart transmission. 478*2468Swnj */ 47913Sbill if (nch) { 480*2468Swnj car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); 481*2468Swnj addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; 482*2468Swnj DELAY(5); 483*2468Swnj unit = 1 << unit; 484*2468Swnj dhsar[dh] |= unit; 485*2468Swnj addr->dhcar = car; 48613Sbill addr->dhbcr = -nch; 487*2468Swnj addr->dhbar |= unit; 48813Sbill tp->t_state |= BUSY; 48913Sbill } 4902395Swnj out: 49113Sbill splx(s); 49213Sbill } 49313Sbill 49413Sbill /* 495*2468Swnj * Stop output on a line, e.g. for ^S/^Q or output flush. 49613Sbill */ 49713Sbill /*ARGSUSED*/ 49813Sbill dhstop(tp, flag) 499*2468Swnj register struct tty *tp; 50013Sbill { 501113Sbill register struct device *addr; 5022395Swnj register int unit, s; 50313Sbill 504113Sbill addr = (struct device *)tp->t_addr; 505*2468Swnj /* 506*2468Swnj * Block input/output interrupts while messing with state. 507*2468Swnj */ 508*2468Swnj s = spl5(); 509113Sbill if (tp->t_state & BUSY) { 510*2468Swnj /* 511*2468Swnj * Device is transmitting; stop output 512*2468Swnj * by selecting the line and setting the byte 513*2468Swnj * count to -1. We will clean up later 514*2468Swnj * by examining the address where the dh stopped. 515*2468Swnj */ 5162395Swnj unit = minor(tp->t_dev); 5172456Swnj addr->un.dhcsrl = (unit&017) | DH_IE; 518*2468Swnj DELAY(5); 51913Sbill if ((tp->t_state&TTSTOP)==0) 52013Sbill tp->t_state |= FLUSH; 521113Sbill addr->dhbcr = -1; 522113Sbill } 52313Sbill splx(s); 52413Sbill } 52513Sbill 526168Sbill /* 527280Sbill * Reset state of driver if UBA reset was necessary. 528280Sbill * Reset the csrl and lpr registers on open lines, and 529280Sbill * restart transmitters. 530280Sbill */ 5312395Swnj dhreset(uban) 532*2468Swnj int uban; 533280Sbill { 5342395Swnj register int dh, unit; 535280Sbill register struct tty *tp; 5362395Swnj register struct uba_dinfo *ui; 5372421Skre int i; 538280Sbill 5392421Skre if (dh_ubinfo[uban] == 0) 5402421Skre return; 541280Sbill printf(" dh"); 5422421Skre ubarelse(uban, &dh_ubinfo[uban]); 5432421Skre dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 5442421Skre 512+NCLIST*sizeof (struct cblock), 0); 5452421Skre cbase[uban] = dh_ubinfo[uban]&0x3ffff; 5462395Swnj dh = 0; 5472421Skre for (dh = 0; dh < NDH11; dh++) { 5482421Skre ui = dhinfo[dh]; 5492421Skre if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 5502421Skre continue; 5512456Swnj ((struct device *)ui->ui_addr)->un.dhcsr |= DH_IE; 552*2468Swnj DELAY(5); 5532456Swnj ((struct device *)ui->ui_addr)->dhsilo = 16; 5542421Skre unit = dh * 16; 5552421Skre for (i = 0; i < 16; i++) { 5562421Skre tp = &dh11[unit]; 5572421Skre if (tp->t_state & (ISOPEN|WOPEN)) { 5582421Skre dhparam(unit); 5592456Swnj dmctl(unit, DM_ON, DMSET); 5602421Skre tp->t_state &= ~BUSY; 5612421Skre dhstart(tp); 5622421Skre } 5632421Skre unit++; 564300Sbill } 565300Sbill } 566300Sbill dhtimer(); 567280Sbill } 5682395Swnj 569*2468Swnj /* 570*2468Swnj * At software clock interrupt time or after a UNIBUS reset 571*2468Swnj * empty all the dh silos. 572*2468Swnj */ 5732456Swnj dhtimer() 5742456Swnj { 5752456Swnj register int dh; 5762456Swnj 5772456Swnj for (dh = 0; dh < NDH11; dh++) 5782456Swnj dhrint(dh); 5792456Swnj } 5802456Swnj 581*2468Swnj /* 582*2468Swnj * DM-11 driver. 583*2468Swnj */ 584*2468Swnj 585*2468Swnj /* 586*2468Swnj * Definition of the controller for the auto-configuration program. 587*2468Swnj */ 588*2468Swnj int dmcntrlr(), dmslave(), dmintr(); 589*2468Swnj struct uba_dinfo *dminfo[NDH11]; 590*2468Swnj u_short dmstd[] = { 0 }; 591*2468Swnj struct uba_driver dmdriver = 592*2468Swnj { dmcntrlr, dmslave, 0, 0, dmstd, "dm", dminfo }; 593*2468Swnj 594*2468Swnj /* hardware bits */ 595*2468Swnj #define DM_CARRTRANS 040000 /* carrier transition */ 596*2468Swnj #define DM_CLSCAN 004000 /* clear scan */ 597*2468Swnj #define DM_DONE 000200 598*2468Swnj #define DM_CARRON 000100 /* carrier on */ 599*2468Swnj #define DM_SCENABLE 000040 /* scan enable */ 600*2468Swnj #define DM_SCBUSY 000020 /* scan busy */ 601*2468Swnj 602*2468Swnj struct dmdevice 603*2468Swnj { 604*2468Swnj short dmcsr; 605*2468Swnj short dmlstat; 606*2468Swnj short dmpad1[2]; 607*2468Swnj }; 608*2468Swnj 609*2468Swnj dmcntrlr(um, addr) 610*2468Swnj struct uba_minfo *um; 611*2468Swnj caddr_t addr; 612*2468Swnj { 613*2468Swnj 614*2468Swnj } 615*2468Swnj 616*2468Swnj dmslave() 617*2468Swnj { 618*2468Swnj 619*2468Swnj } 620*2468Swnj 621*2468Swnj /* 622*2468Swnj * Turn on the line associated with the dh device dev. 623*2468Swnj */ 624*2468Swnj dmopen(dev) 625*2468Swnj dev_t dev; 626*2468Swnj { 627*2468Swnj register struct tty *tp; 628*2468Swnj register struct dmdevice *addr; 629*2468Swnj register struct uba_dinfo *ui; 630*2468Swnj register int unit; 631*2468Swnj register int dm; 632*2468Swnj 633*2468Swnj unit = minor(dev); 634*2468Swnj dm = unit >> 8; 635*2468Swnj tp = &dh11[unit]; 636*2468Swnj if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { 637*2468Swnj tp->t_state |= CARR_ON; 638*2468Swnj return; 639*2468Swnj } 640*2468Swnj addr = (struct dmdevice *)ui->ui_addr; 641*2468Swnj spl5(); 642*2468Swnj addr->dmcsr &= ~DM_SCENABLE; 643*2468Swnj while (addr->dmcsr & DM_SCBUSY) 644*2468Swnj ; 645*2468Swnj addr->dmcsr = unit & 0xf; 646*2468Swnj addr->dmlstat = DM_ON; 647*2468Swnj if (addr->dmlstat&DM_CARRON) 648*2468Swnj tp->t_state |= CARR_ON; 649*2468Swnj addr->dmcsr = DH_IE|DM_SCENABLE; 650*2468Swnj while ((tp->t_state&CARR_ON)==0) 651*2468Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 652*2468Swnj spl0(); 653*2468Swnj } 654*2468Swnj 655*2468Swnj /* 656*2468Swnj * Dump control bits into the DM registers. 657*2468Swnj */ 658*2468Swnj dmctl(dev, bits, how) 659*2468Swnj dev_t dev; 660*2468Swnj int bits, how; 661*2468Swnj { 662*2468Swnj register struct uba_dinfo *ui; 663*2468Swnj register struct dmdevice *addr; 664*2468Swnj register int unit, s; 665*2468Swnj int dm; 666*2468Swnj 667*2468Swnj unit = minor(dev); 668*2468Swnj dm = unit >> 4; 669*2468Swnj if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) 670*2468Swnj return; 671*2468Swnj addr = (struct dmdevice *)ui->ui_addr; 672*2468Swnj s = spl5(); 673*2468Swnj addr->dmcsr &= ~DM_SCENABLE; 674*2468Swnj while (addr->dmcsr & DM_SCBUSY) 675*2468Swnj ; 676*2468Swnj addr->dmcsr = unit & 0xf; 677*2468Swnj switch(how) { 678*2468Swnj case DMSET: 679*2468Swnj addr->dmlstat = bits; 680*2468Swnj break; 681*2468Swnj case DMBIS: 682*2468Swnj addr->dmlstat |= bits; 683*2468Swnj break; 684*2468Swnj case DMBIC: 685*2468Swnj addr->dmlstat &= ~bits; 686*2468Swnj break; 687*2468Swnj } 688*2468Swnj addr->dmcsr = DH_IE|DM_SCENABLE; 689*2468Swnj splx(s); 690*2468Swnj } 691*2468Swnj 692*2468Swnj /* 693*2468Swnj * DM11 interrupt; deal with carrier transitions. 694*2468Swnj */ 695*2468Swnj dmintr(dm) 696*2468Swnj register int dm; 697*2468Swnj { 698*2468Swnj register struct uba_dinfo *ui; 699*2468Swnj register struct tty *tp; 700*2468Swnj register struct dmdevice *addr; 701*2468Swnj 702*2468Swnj ui = dminfo[dm]; 703*2468Swnj addr = (struct dmdevice *)ui->ui_addr; 704*2468Swnj if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CARRTRANS) { 705*2468Swnj tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; 706*2468Swnj wakeup((caddr_t)&tp->t_rawq); 707*2468Swnj if ((tp->t_state&WOPEN)==0 && 708*2468Swnj (tp->t_local&LMDMBUF)) { 709*2468Swnj if (addr->dmlstat & DM_CARRON) { 710*2468Swnj tp->t_state &= ~TTSTOP; 711*2468Swnj ttstart(tp); 712*2468Swnj } else if ((tp->t_state&TTSTOP) == 0) { 713*2468Swnj tp->t_state |= TTSTOP; 714*2468Swnj dhstop(tp, 0); 715*2468Swnj } 716*2468Swnj } else if ((addr->dmlstat&DM_CARRON)==0) { 717*2468Swnj if ((tp->t_state&WOPEN)==0 && 718*2468Swnj (tp->t_local&LNOHANG)==0) { 719*2468Swnj gsignal(tp->t_pgrp, SIGHUP); 720*2468Swnj gsignal(tp->t_pgrp, SIGCONT); 721*2468Swnj addr->dmlstat = 0; 722*2468Swnj flushtty(tp, FREAD|FWRITE); 723*2468Swnj } 724*2468Swnj tp->t_state &= ~CARR_ON; 725*2468Swnj } else 726*2468Swnj tp->t_state |= CARR_ON; 727*2468Swnj addr->dmcsr = DH_IE|DM_SCENABLE; 728*2468Swnj } 729*2468Swnj } 730