1*2395Swnj /* dz.c 4.10 02/10/81 */ 217Sbill 31935Swnj #include "dz.h" 41562Sbill #if NDZ11 > 0 517Sbill /* 617Sbill * DZ-11 Driver 717Sbill */ 817Sbill #include "../h/param.h" 917Sbill #include "../h/systm.h" 1017Sbill #include "../h/tty.h" 1117Sbill #include "../h/dir.h" 1217Sbill #include "../h/user.h" 1317Sbill #include "../h/map.h" 1417Sbill #include "../h/pte.h" 15*2395Swnj #include "../h/buf.h" 1617Sbill #include "../h/uba.h" 1717Sbill #include "../h/conf.h" 1817Sbill #include "../h/pdma.h" 19114Sbill #include "../h/bk.h" 20871Sbill #include "../h/file.h" 211786Sbill #include "../h/mx.h" 22145Sbill 23145Sbill /* 24145Sbill * When running dz's using only SAE (silo alarm) on input 25145Sbill * it is necessary to call dzrint() at clock interrupt time. 26145Sbill * This is unsafe unless spl5()s in tty code are changed to 27145Sbill * spl6()s to block clock interrupts. Note that the dh driver 28145Sbill * currently in use works the same way as the dz, even though 29145Sbill * we could try to more intelligently manage its silo. 30145Sbill * Thus don't take this out if you have no dz's unless you 31145Sbill * change clock.c and dhtimer(). 32*2395Swnj * 33*2395Swnj * SHOULD RATHER QUEUE SOFTWARE INTERRUPT AT CLOCK TIME. 34145Sbill */ 35145Sbill #define spl5 spl6 3617Sbill 37*2395Swnj int dzcntrlr(), dzslave(), dzrint(); 38*2395Swnj struct uba_dinfo *dzinfo[NDZ11]; 39*2395Swnj u_short dzstd[] = { 0 }; 40*2395Swnj int (*dzivec[])() = { dzrint, 0 }; /* omit dzxint so we can do it here */ 41*2395Swnj struct uba_driver dzdriver = 42*2395Swnj { dzcntrlr, dzslave, (int (*)())0, 0, 0, dzstd, dzinfo, dzivec }; 43*2395Swnj 44882Sbill #define NDZ (NDZ11*8) 4517Sbill 4617Sbill #define BITS7 020 4717Sbill #define BITS8 030 4817Sbill #define TWOSB 040 4917Sbill #define PENABLE 0100 5017Sbill #define OPAR 0200 5117Sbill #define MSE 040 /* Master Scan Enable */ 5217Sbill #define RIE 0100 /* Receiver Interrupt Enable */ 53119Sbill #define SAE 010000 /* Silo Alarm Enable */ 54119Sbill #define TIE 040000 /* Transmit Interrupt Enable */ 55119Sbill #define DZ_IEN (MSE+RIE+TIE+SAE) 5617Sbill #define PERROR 010000 5717Sbill #define FRERROR 020000 58119Sbill #define OVERRUN 040000 5917Sbill #define SSPEED 7 /* std speed = 300 baud */ 6017Sbill 6117Sbill #define dzlpr dzrbuf 6217Sbill #define dzmsr dzbrk 6317Sbill #define ON 1 6417Sbill #define OFF 0 6517Sbill 6617Sbill int dzstart(); 6717Sbill int dzxint(); 68*2395Swnj int dzdma(); 69114Sbill int ttrstrt(); 7017Sbill struct tty dz_tty[NDZ]; 7117Sbill int dz_cnt = { NDZ }; 72119Sbill int dzact; 7317Sbill 7417Sbill struct device { 7517Sbill short dzcsr; 7617Sbill short dzrbuf; 7717Sbill char dztcr; 7817Sbill char dzdtr; 7917Sbill char dztbuf; 8017Sbill char dzbrk; 8117Sbill }; 8217Sbill 83*2395Swnj struct pdma dzpdma[NDZ]; 8417Sbill char dz_timer; 85*2395Swnj char dz_speeds[] = 86*2395Swnj { 0,020,021,022,023,024,0,025,026,027,030,032,034,036,0,0 }; 87*2395Swnj char dz_brk[NDZ11]; 8817Sbill 89*2395Swnj dzcntrlr(ui, reg) 90*2395Swnj struct uba_dinfo *ui; 91*2395Swnj caddr_t reg; 92*2395Swnj { 93*2395Swnj 94*2395Swnj ((struct device *)reg)->dzcsr |= IENABLE; 95*2395Swnj /* get it to interrupt */ 96*2395Swnj } 97*2395Swnj 98*2395Swnj dzslave(ui, reg, slaveno, uban) 99*2395Swnj register struct uba_dinfo *ui; 100*2395Swnj caddr_t reg; 101*2395Swnj { 102*2395Swnj register struct pdma *pdp = &dzpdma[ui->ui_unit*8]; 103*2395Swnj register struct tty *tp = &dz_tty[ui->ui_unit*8]; 104*2395Swnj register int cnt; 105*2395Swnj register int *urk = (int *)(® - 24); /* white magic */ 106*2395Swnj caddr_t cp; 107*2395Swnj int urk2; 108*2395Swnj 109*2395Swnj for (cnt = 0; cnt < 8; cnt++) { 110*2395Swnj pdp->p_addr = (struct device *)reg; 111*2395Swnj pdp->p_arg = (int)tp; 112*2395Swnj pdp->p_fcn = dzxint; 113*2395Swnj pdp++, tp++; 114*2395Swnj } 115*2395Swnj if ((cp = calloc(12)) == 0) 116*2395Swnj panic("dz iv nm\n"); 117*2395Swnj uba_hd[uban].uh_vec[*urk] = (int (*)())cp; /* more white magic */ 118*2395Swnj *cp++ = 0xbb; *cp++ = 0xff; *cp++ = 0xd0; /* black magic */ 119*2395Swnj *cp++ = ui->ui_unit&0x3f; *cp++ = 0x50; 120*2395Swnj *cp++ = 0x17; *cp++ = 0x9f; 121*2395Swnj urk2 = (int)dzdma; 122*2395Swnj for (cnt = 0; cnt < 4; cnt++) 123*2395Swnj *cp++ = urk2, urk2 >>= 4; /* the spell ends */ 124*2395Swnj return (1); 125*2395Swnj } 126*2395Swnj 12717Sbill /*ARGSUSED*/ 128*2395Swnj dzopen(dev, flag) 129*2395Swnj dev_t dev; 13017Sbill { 13117Sbill register struct tty *tp; 132*2395Swnj register int unit; 13317Sbill extern dzscan(); 13417Sbill 135*2395Swnj unit = minor(dev); 136*2395Swnj if (unit >= dz_cnt || dzpdma[unit].p_addr == 0) { 13717Sbill u.u_error = ENXIO; 13817Sbill return; 13917Sbill } 14017Sbill if (dz_timer == 0) { 14117Sbill dz_timer++; 14217Sbill timeout(dzscan, (caddr_t)0, 60); 14317Sbill } 144*2395Swnj tp = &dz_tty[unit]; 145*2395Swnj tp->t_addr = (caddr_t)&dzpdma[unit]; 14617Sbill tp->t_oproc = dzstart; 14717Sbill tp->t_iproc = NULL; 14817Sbill tp->t_state |= WOPEN; 14917Sbill if ((tp->t_state & ISOPEN) == 0) { 15017Sbill ttychars(tp); 15117Sbill tp->t_ospeed = tp->t_ispeed = SSPEED; 15217Sbill tp->t_flags = ODDP|EVENP|ECHO; 15317Sbill /*tp->t_state |= HUPCLS;*/ 154*2395Swnj dzparam(unit); 15517Sbill } else if (tp->t_state&XCLUDE && u.u_uid != 0) { 15617Sbill u.u_error = EBUSY; 15717Sbill return; 15817Sbill } 159*2395Swnj dzmodem(unit, ON); 160114Sbill (void) spl5(); 16117Sbill while ((tp->t_state & CARR_ON) == 0) { 16217Sbill tp->t_state |= WOPEN; 16317Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 16417Sbill } 165114Sbill (void) spl0(); 166*2395Swnj (*linesw[tp->t_line].l_open)(dev, tp); 16717Sbill } 16817Sbill 169*2395Swnj /*ARGSUSED*/ 170*2395Swnj dzclose(dev, flag) 171*2395Swnj dev_t dev; 17217Sbill { 17317Sbill register struct tty *tp; 174*2395Swnj register int unit; 175*2395Swnj int dz; 17617Sbill 177*2395Swnj unit = minor(dev); 178*2395Swnj dz = unit >> 3; 179*2395Swnj tp = &dz_tty[unit]; 18017Sbill (*linesw[tp->t_line].l_close)(tp); 1812197Stoy ((struct pdma *)(tp->t_addr))->p_addr->dzbrk = 182*2395Swnj (dz_brk[dz] &= ~(1 << (unit&07))); 18317Sbill if (tp->t_state & HUPCLS) 184*2395Swnj dzmodem(unit, OFF); 18517Sbill ttyclose(tp); 18617Sbill } 18717Sbill 188*2395Swnj dzread(dev) 189*2395Swnj dev_t dev; 19017Sbill { 19117Sbill register struct tty *tp; 19217Sbill 193*2395Swnj tp = &dz_tty[minor(dev)]; 19417Sbill (*linesw[tp->t_line].l_read)(tp); 19517Sbill } 19617Sbill 197*2395Swnj dzwrite(dev) 198*2395Swnj dev_t dev; 19917Sbill { 20017Sbill register struct tty *tp; 20117Sbill 202*2395Swnj tp = &dz_tty[minor(dev)]; 20317Sbill (*linesw[tp->t_line].l_write)(tp); 20417Sbill } 20517Sbill 206119Sbill /*ARGSUSED*/ 207*2395Swnj dzrint(dz) 208*2395Swnj int dz; 20917Sbill { 21017Sbill register struct tty *tp; 21117Sbill register int c; 21217Sbill register struct device *dzaddr; 213119Sbill register struct tty *tp0; 214*2395Swnj register int unit; 215140Sbill int s; 21617Sbill 217140Sbill s = spl6(); /* see comment in clock.c */ 218119Sbill /* as long as we are here, service them all */ 219*2395Swnj for (unit = 0; unit < NDZ; unit += 8) { 220*2395Swnj if ((dzact & (1<<(unit>>3))) == 0) 22117Sbill continue; 222*2395Swnj dzaddr = dzpdma[unit].p_addr; 223*2395Swnj tp0 = &dz_tty[unit]; 224119Sbill while ((c = dzaddr->dzrbuf) < 0) { /* char present */ 225119Sbill tp = tp0 + ((c>>8)&07); 226119Sbill if (tp >= &dz_tty[dz_cnt]) 22717Sbill continue; 228119Sbill if ((tp->t_state & ISOPEN) == 0) { 229119Sbill wakeup((caddr_t)&tp->t_rawq); 230119Sbill continue; 231119Sbill } 232119Sbill if (c&FRERROR) 233119Sbill /* framing error = break */ 234119Sbill if (tp->t_flags & RAW) 235119Sbill c = 0; /* null for getty */ 236119Sbill else 237170Sbill #ifdef IIASA 238170Sbill continue; 239170Sbill #else 240185Sbill c = tun.t_intrc; 241170Sbill #endif 242119Sbill if (c&OVERRUN) 243119Sbill printf("o"); 244119Sbill if (c&PERROR) 245119Sbill /* parity error */ 246119Sbill if (((tp->t_flags & (EVENP|ODDP)) == EVENP) 247119Sbill || ((tp->t_flags & (EVENP|ODDP)) == ODDP)) 248119Sbill continue; 249140Sbill if (tp->t_line == NETLDISC) { 250114Sbill c &= 0177; 251170Sbill BKINPUT(c, tp); 252114Sbill } else 253114Sbill (*linesw[tp->t_line].l_rint)(c, tp); 254119Sbill } 25517Sbill } 256140Sbill splx(s); 25717Sbill } 25817Sbill 25917Sbill /*ARGSUSED*/ 26017Sbill dzioctl(dev, cmd, addr, flag) 261*2395Swnj dev_t dev; 262*2395Swnj caddr_t addr; 26317Sbill { 26417Sbill register struct tty *tp; 265*2395Swnj register int unit = minor(dev); 266*2395Swnj register int dz = unit >> 3; 26717Sbill 268*2395Swnj tp = &dz_tty[unit]; 269114Sbill cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); 270114Sbill if (cmd == 0) 271114Sbill return; 2721896Swnj if (ttioctl(tp, cmd, addr, flag)) { 27317Sbill if (cmd==TIOCSETP || cmd==TIOCSETN) 274*2395Swnj dzparam(unit); 275170Sbill } else switch(cmd) { 276*2395Swnj 277170Sbill case TIOCSBRK: 278882Sbill ((struct pdma *)(tp->t_addr))->p_addr->dzbrk = 279*2395Swnj (dz_brk[dz] |= 1 << (unit&07)); 280170Sbill break; 281170Sbill case TIOCCBRK: 282882Sbill ((struct pdma *)(tp->t_addr))->p_addr->dzbrk = 283*2395Swnj (dz_brk[dz] &= ~(1 << (unit&07))); 284170Sbill break; 285170Sbill case TIOCSDTR: 286*2395Swnj dzmodem(unit, ON); 287170Sbill break; 288170Sbill case TIOCCDTR: 289*2395Swnj dzmodem(unit, OFF); 290170Sbill break; 291170Sbill default: 29217Sbill u.u_error = ENOTTY; 293170Sbill } 29417Sbill } 29517Sbill 296*2395Swnj dzparam(unit) 297*2395Swnj register int unit; 29817Sbill { 29917Sbill register struct tty *tp; 30017Sbill register struct device *dzaddr; 301*2395Swnj register int lpr; 30217Sbill 303*2395Swnj tp = &dz_tty[unit]; 304*2395Swnj dzaddr = dzpdma[unit].p_addr; 30517Sbill dzaddr->dzcsr = DZ_IEN; 306*2395Swnj dzact |= (1<<(unit>>3)); 30717Sbill if (tp->t_ispeed == 0) { 308*2395Swnj dzmodem(unit, OFF); /* hang up line */ 30917Sbill return; 31017Sbill } 311*2395Swnj lpr = (dz_speeds[tp->t_ispeed]<<8) | (unit & 07); 312882Sbill #ifndef IIASA 3132296Swnj if ((tp->t_local&LLITOUT) || (tp->t_flags&RAW)) 31417Sbill lpr |= BITS8; 31517Sbill else 31617Sbill lpr |= (BITS7|PENABLE); 31717Sbill if ((tp->t_flags & EVENP) == 0) 31817Sbill lpr |= OPAR; 319882Sbill #else IIASA 320882Sbill if ((tp->t_flags & (EVENP|ODDP)) == (EVENP|ODDP)) 321882Sbill lpr |= BITS8; 322882Sbill else if (tp->t_flags & EVENP) 323882Sbill lpr |= (BITS7|PENABLE); 324882Sbill else if (tp->t_flags & ODDP) 325882Sbill lpr |= (BITS7|OPAR|PENABLE); 326882Sbill else 327882Sbill lpr |= BITS7; 328882Sbill #endif IIASA 32917Sbill if (tp->t_ispeed == 3) 33017Sbill lpr |= TWOSB; /* 110 baud: 2 stop bits */ 33117Sbill dzaddr->dzlpr = lpr; 33217Sbill } 33317Sbill 33417Sbill dzxint(tp) 335*2395Swnj register struct tty *tp; 33617Sbill { 33717Sbill register struct pdma *dp; 338145Sbill register s; 339145Sbill s = spl6(); /* block the clock */ 34017Sbill 341*2395Swnj dp = (struct pdma *)tp->t_addr; 34217Sbill tp->t_state &= ~BUSY; 34317Sbill if (tp->t_state & FLUSH) 34417Sbill tp->t_state &= ~FLUSH; 34517Sbill else 346281Sbill ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf); 34717Sbill if (tp->t_line) 34817Sbill (*linesw[tp->t_line].l_start)(tp); 34917Sbill else 35017Sbill dzstart(tp); 35117Sbill if (tp->t_outq.c_cc == 0 || (tp->t_state&BUSY)==0) 352*2395Swnj dp->p_addr->dztcr &= ~(1 << (minor(tp->t_dev)&07)); 353145Sbill splx(s); 35417Sbill } 35517Sbill 35617Sbill dzstart(tp) 357*2395Swnj register struct tty *tp; 35817Sbill { 35917Sbill register struct pdma *dp; 36017Sbill register struct device *dzaddr; 361*2395Swnj register int cc; 362*2395Swnj int s; 36317Sbill 364*2395Swnj dp = (struct pdma *)tp->t_addr; 36517Sbill dzaddr = dp->p_addr; 366*2395Swnj s = spl5(); 36717Sbill if (tp->t_state & (TIMEOUT|BUSY|TTSTOP)) 36817Sbill goto out; 369921Sbill if (tp->t_state&ASLEEP && tp->t_outq.c_cc <= TTLOWAT(tp)) { 37017Sbill tp->t_state &= ~ASLEEP; 37117Sbill if (tp->t_chan) 37217Sbill mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 37317Sbill else 37417Sbill wakeup((caddr_t)&tp->t_outq); 37517Sbill } 37617Sbill if (tp->t_outq.c_cc == 0) 37717Sbill goto out; 37817Sbill if (tp->t_flags&RAW) 37917Sbill cc = ndqb(&tp->t_outq, 0); 38017Sbill else { 38117Sbill cc = ndqb(&tp->t_outq, 0200); 38217Sbill if (cc == 0) { 38317Sbill cc = getc(&tp->t_outq); 38417Sbill timeout(ttrstrt, (caddr_t)tp, (cc&0177) + 6); 38517Sbill tp->t_state |= TIMEOUT; 38617Sbill goto out; 38717Sbill } 38817Sbill } 38917Sbill tp->t_state |= BUSY; 39017Sbill dp->p_end = dp->p_mem = tp->t_outq.c_cf; 39117Sbill dp->p_end += cc; 392*2395Swnj dzaddr->dztcr |= 1 << (minor(tp->t_dev) & 07); 393*2395Swnj out: 394*2395Swnj splx(s); 39517Sbill } 39617Sbill 39717Sbill /* 39817Sbill * Stop output on a line. 39917Sbill * Assume call is made at spl6. 40017Sbill */ 40117Sbill /*ARGSUSED*/ 40217Sbill dzstop(tp, flag) 403*2395Swnj register struct tty *tp; 40417Sbill { 40517Sbill register struct pdma *dp; 40617Sbill register int s; 40717Sbill 408*2395Swnj dp = (struct pdma *)tp->t_addr; 40917Sbill s = spl6(); 41017Sbill if (tp->t_state & BUSY) { 41117Sbill dp->p_end = dp->p_mem; 412*2395Swnj if ((tp->t_state&TTSTOP)==0) 41317Sbill tp->t_state |= FLUSH; 41417Sbill } 41517Sbill splx(s); 41617Sbill } 41717Sbill 418*2395Swnj dzmodem(unit, flag) 419*2395Swnj register int unit; 42017Sbill { 42117Sbill register struct device *dzaddr; 42217Sbill register char bit; 42317Sbill 424*2395Swnj dzaddr = dzpdma[unit].p_addr; 425*2395Swnj bit = 1<<(unit&07); 42617Sbill if (flag == OFF) 42717Sbill dzaddr->dzdtr &= ~bit; 42817Sbill else 42917Sbill dzaddr->dzdtr |= bit; 43017Sbill } 43117Sbill 43217Sbill dzscan() 43317Sbill { 43417Sbill register i; 43517Sbill register struct device *dzaddr; 43617Sbill register bit; 43717Sbill register struct tty *tp; 43817Sbill 43917Sbill for (i = 0; i < dz_cnt ; i++) { 44017Sbill dzaddr = dzpdma[i].p_addr; 44117Sbill tp = &dz_tty[i]; 44217Sbill bit = 1<<(i&07); 4432379Swnj if (dzaddr->dzmsr & bit || (i == 6 || i == 7)) { 44417Sbill /* carrier present */ 44517Sbill if ((tp->t_state & CARR_ON) == 0) { 44617Sbill wakeup((caddr_t)&tp->t_rawq); 44717Sbill tp->t_state |= CARR_ON; 44817Sbill } 44917Sbill } else { 450*2395Swnj if ((tp->t_state&CARR_ON) && (tp->t_local&LNOHANG)==0) { 45117Sbill /* carrier lost */ 452882Sbill if (tp->t_state&ISOPEN) { 453170Sbill gsignal(tp->t_pgrp, SIGHUP); 454205Sbill gsignal(tp->t_pgrp, SIGCONT); 455170Sbill dzaddr->dzdtr &= ~bit; 456871Sbill flushtty(tp, FREAD|FWRITE); 457170Sbill } 458170Sbill tp->t_state &= ~CARR_ON; 45917Sbill } 46017Sbill } 46117Sbill } 46217Sbill timeout(dzscan, (caddr_t)0, 2*HZ); 46317Sbill } 464119Sbill 465119Sbill dztimer() 466119Sbill { 467119Sbill 468119Sbill dzrint(0); 469119Sbill } 470281Sbill 471281Sbill /* 472281Sbill * Reset state of driver if UBA reset was necessary. 473301Sbill * Reset parameters and restart transmission on open lines. 474281Sbill */ 475*2395Swnj dzreset(uban) 476281Sbill { 477*2395Swnj register int unit; 478281Sbill register struct tty *tp; 479281Sbill 480*2395Swnj /*** WE SHOULD LOOK TO SEE IF WE CARE ABOUT UBA BEING RESET ***/ 481*2395Swnj 482281Sbill printf(" dz"); 483*2395Swnj for (unit = 0; unit < NDZ; unit++) { 484*2395Swnj tp = &dz_tty[unit]; 485281Sbill if (tp->t_state & (ISOPEN|WOPEN)) { 486*2395Swnj dzparam(unit); 487*2395Swnj dzmodem(unit, ON); 488301Sbill tp->t_state &= ~BUSY; 489301Sbill dzstart(tp); 490281Sbill } 491281Sbill } 492281Sbill dztimer(); 493281Sbill } 4941562Sbill #endif 495