/* * UTS driver for DZ-11 with KMC assist */ #include "sys/param.h" #include "sys/dir.h" #include "sys/user.h" #include "sys/file.h" #include "sys/tty.h" #include "sys/conf.h" #include "sys/ioctl.h" #include "sys/uba.h" #include "sys/sysinfo.h" struct device *dza_addr[]; int dza_cnt; struct tty dza_tty[]; short dza_scan; short dza_stat; short dza_kmc[8]; char dza_brk[8]; /* break bits - max 64 lines */ char dza_speeds[16] = { 0, 00, 01, 02, 03, 04, 0, 05, 06, 07, 010, 012, 014, 016, 0, 0 }; /* * Define op codes for commands to the KMC */ #define XBUFIN 0 #define IOCTL 1 #define BASEIN 2 #define CMDIN 3 /* * Define sub command bits for CMDIN */ #define OFLUSH (1<<1) /* Flush output */ #define OSPND (1<<2) /* Suspend output */ #define ORSME (1<<3) /* Resume output */ #define SCHAR (1<<4) /* Send character in csr6 */ #define BITS6 010 #define BITS7 020 #define TWOSB 040 #define PENABLE 0100 #define OPAR 0200 #define RCVENB 010000 #define IE 0140 struct device { short dzacsr, dzarbuf; char dzatcr, dzadtr; char dzatbuf, dzabrk; }; #define dzalpr dzarbuf #define dzamsr dzabrk #define ON 1 #define OFF 0 dzaopen(dev, flag) { register struct tty *tp; register kf; extern dzaproc(), dzakint(); if ((dev&077) >= dza_cnt) { u.u_error = ENXIO; return; } kf = 1<<(((dev>>6)&03)+8); if ((dza_stat&kf) == 0) { if (kmcset(dev,03,dzakint)) { u.u_error = ENXIO; return; } dza_stat |= kf; } tp = &dza_tty[dev&077]; if ((tp->t_state&(ISOPEN|WOPEN)) == 0) { ttinit(tp); tp->t_proc = dzaproc; tp->t_state |= EXTPROC; dzaparam(dev); } spl5(); if (tp->t_cflag&CLOCAL || dzamodem(dev, ON)) tp->t_state |= CARR_ON; else tp->t_state &= ~CARR_ON; if (!(flag&FNDELAY)) while ((tp->t_state&CARR_ON)==0) { tp->t_state |= WOPEN; sleep((caddr_t)&tp->t_canq, TTIPRI); } (*linesw[tp->t_line].l_open)(tp); spl0(); } dzaclose(dev) { register struct tty *tp; tp = &dza_tty[dev&077]; (*linesw[tp->t_line].l_close)(tp); if (tp->t_cflag&HUPCL) dzamodem(dev, OFF); } dzaread(dev) { register struct tty *tp; tp = &dza_tty[dev&077]; (*linesw[tp->t_line].l_read)(tp); } dzawrite(dev) { register struct tty *tp; tp = &dza_tty[dev&077]; (*linesw[tp->t_line].l_write)(tp); } dzaioctl(dev, cmd, arg, mode) register dev; { switch(cmd) { default: if (ttiocom(&dza_tty[dev&077], cmd, arg, mode)) dzaparam(dev); } } dzaparam(dev) { register struct tty *tp; register struct device *dzaaddr; register flags, lpr; register struct cblock *cp; register i; tp = &dza_tty[dev&077]; dzaaddr= dza_addr[(dev>>3)&07]; dzaaddr->dzacsr = IE; if (dza_scan==0) { dzascan(); dza_scan++; } flags = tp->t_cflag; if ((flags&CBAUD) == 0) { /* hang up line */ dzamodem(dev, OFF); return; } lpr = (dza_speeds[flags&CBAUD]<<8)|(dev&07); if (flags&CREAD) lpr |= RCVENB; if (flags&CS6) lpr |= BITS6; if (flags&CS7) lpr |= BITS7; if (flags&PARENB) { lpr |= PENABLE; if (flags&PARODD) lpr |= OPAR; } if (flags&CSTOPB) lpr |= TWOSB; dzaaddr->dzalpr = lpr; /* * Now pass the relevant parameters to the KMC */ lpr = (dev>>3)&07; if ((dza_stat&(1<<lpr)) == 0) { dza_kmc[lpr] = dev&0370; kmcload(dza_kmc[lpr]|(dev&07),BASEIN,(int)dza_addr[lpr]-UBA_DEV,0); dza_stat |= 1<<lpr; } kmcload(dza_kmc[lpr]|(dev&07),IOCTL,tp->t_oflag,0); } dzarint(dev) { register struct tty *tp; register c; register line; register struct device *dzaaddr; sysinfo.rcvint++; dzaaddr = dza_addr[dev]; while ((c = dzaaddr->dzarbuf) < 0) { /* char. present */ line = (c>>8)&07; tp = &dza_tty[line|(dev<<3)]; if (tp >= &dza_tty[dza_cnt]) continue; if (!(tp->t_state&(ISOPEN|WOPEN))) continue; if (tp->t_cflag&CLOCAL || dzaaddr->dzamsr&(1<<line)) { if ((tp->t_state&CARR_ON) == 0) { wakeup(&tp->t_canq); tp->t_state |= CARR_ON; } } else { if (tp->t_state&CARR_ON) { signal(tp->t_pgrp, SIGHUP); dzaaddr->dzadtr &= ~(1<<line); tp->t_state &= ~CARR_ON; ttyflush(tp, (FREAD|FWRITE)); } continue; } (*linesw[tp->t_line].l_input)(tp, c, 0); } } dzaxint(dev) { printf("dza: xint\n"); } /* * Routine to handle interrupts from the KMC * This routine gets called from the KMC driver whenever * the KMC generates an unsolicited interrupt (VEC4 == 1) * * These interrupts are used by the KMC to notify dza.c * of events such as output buffer completions */ dzakint(dev, sel2, sel4, sel6) { register struct tty *tp; register ttybit, bar; int dznr; sysinfo.xmtint++; ttybit = 1; bar = sel4&0377; dznr = dev&07; for (tp = &dza_tty[dznr<<3]; bar; tp++) { if (bar&ttybit) { bar &= ~ttybit; tp->t_state &= ~BUSY; dzaproc(tp, T_OUTPUT); } ttybit <<= 1; } } dzaproc(tp, cmd) register struct tty *tp; { extern ttrstrt(); char *cp; int unit; struct device *dzaaddr; register dev; register sel4, sel6; register n; dev = tp - dza_tty; dzaaddr = dza_addr[dev>>3]; unit = 1<<(dev&07); sel4 = 0; switch(cmd) { case T_TIME: tp->t_state &= ~TIMEOUT; dza_brk[dev>>3] &= ~unit; dzaaddr->dzabrk = dza_brk[dev>>3]; goto start; case T_WFLUSH: sel4 |= OFLUSH; case T_RESUME: tp->t_state &= ~TTSTOP; sel4 |= ORSME; goto start; case T_OUTPUT: start: if (tp->t_state&(TIMEOUT|TTSTOP|BUSY)) break; if (tp->t_state&TTIOW && tp->t_outq.c_cc==0) { tp->t_state &= ~TTIOW; wakeup((caddr_t)&tp->t_oflag); } if (tp->t_buf!=NULL) putcf(tp->t_buf); if ((tp->t_buf = getcb(&tp->t_outq)) != NULL) { paddr_t addr; n = tp->t_buf->c_last - tp->t_buf->c_first; cp = &tp->t_buf->c_data[tp->t_buf->c_first]; addr = ubmdata(cp); if (kmcload(dza_kmc[(dev>>3)&07]|(dev&07), XBUFIN, loword(addr), (hiword(addr)<<14|(n&0377))) < 0) goto start; tp->t_state |= BUSY; } if (tp->t_state&OASLP && tp->t_outq.c_cc<=ttlowat[tp->t_cflag&CBAUD]) { tp->t_state &= ~OASLP; wakeup((caddr_t)&tp->t_outq); } break; case T_SUSPEND: tp->t_state |= TTSTOP; sel4 |= OSPND; break; case T_BLOCK: tp->t_state |= TBLOCK; sel4 |= SCHAR; sel6 = CSTOP; break; case T_RFLUSH: if (!(tp->t_state&TBLOCK)) break; case T_UNBLOCK: tp->t_state &= ~TBLOCK; sel4 |= SCHAR; sel6 = CSTART; break; case T_BREAK: dza_brk[dev>>3] |= unit; dzaaddr->dzabrk = dza_brk[dev>>3]; tp->t_state |= TIMEOUT; timeout(ttrstrt, tp, HZ/4); break; } if (sel4) kmcload(dza_kmc[(dev>>3)&07]|(dev&07), CMDIN, sel4, sel6); } dzamodem(dev, flag) { register struct device *dzaaddr; register bit; dzaaddr = dza_addr[(dev>>3)&07]; bit = 1<<(dev&07); if (flag==OFF) dzaaddr->dzadtr &= ~bit; else dzaaddr->dzadtr |= bit; return(dzaaddr->dzamsr & bit); } dzascan() { register i; register struct device *dzaaddr; register struct tty *tp; char bit; for (i=0; i<dza_cnt; i++) { tp = &dza_tty[i]; if (!(tp->t_state&(ISOPEN|WOPEN))) continue; dzaaddr = dza_addr[i>>3]; bit = 1<<(i&07); if (tp->t_cflag&CLOCAL || dzaaddr->dzamsr&bit) { if ((tp->t_state&CARR_ON)==0) { wakeup(&tp->t_canq); tp->t_state |= CARR_ON; } } else { if (tp->t_state&CARR_ON) { if (tp->t_state&ISOPEN) { signal(tp->t_pgrp, SIGHUP); dzaaddr->dzadtr &= ~bit; ttyflush(tp, (FREAD|FWRITE)); } tp->t_state &= ~CARR_ON; } } } timeout(dzascan, 0, 120); } dzaclr() { register dev; register struct tty *tp; if (dza_stat == 0) return; for (dev = 0; dev < 4; dev++) if (dza_stat&(1<<(dev+8))) kmcdclr(dev); dza_stat = 0; for (dev = 0; dev < dza_cnt; dev++) { tp = &dza_tty[dev]; if ((tp->t_state&(ISOPEN|WOPEN)) == 0) continue; dzaparam(dza_kmc[(dev>>3)&07]|(dev&07)); dzamodem(dev, ON); tp->t_state &= ~BUSY; dzaproc(tp, T_OUTPUT); } }