/* * TTY 40/4 driver for VAX 11/780 */ #include "sys/param.h" #include "sys/st.h" #include "sys/dir.h" #include "sys/map.h" #include "sys/user.h" #include "sys/proc.h" #include "sys/buf.h" #define NULL 0 #define STMPRI (PZERO + 1) /* allow interrupted reads */ #define stid(X) (unsigned)((X->sm_sta << 8) | X->sm_dev) extern struct st st_st[]; /* sync channels */ extern int st_cnt; /* number of channels */ extern int _sdata; struct map stomap[STMAP]; /* map for alloc of stbuf */ struct map stimap[STMAP]; /* map for alloc of stbuf */ struct stbhdr sthdrb[STHBUF]; /* header buffer pool */ struct buf sthdr; /* mask for bigetc use */ unsigned wrccnt; int stoflg, sthflg; char stobuf[STOBSZ]; char stibuf[STIBSZ]; int stibase, stobase; struct stbhdr *ffree; unsigned sthdcnt = 0; unsigned stopflg; unsigned ttyid[NKMC]; stopen(dev) int dev; { register struct st *dp; register struct stmsghdr *hp; register int *ip; dp = &st_st[dev]; if(dev >= st_cnt) { u.u_error = ENXIO; return; } spl5(); if ((dp->s_flags & CH_OPEN) == NULL) { ip = (int *)dp; while (ip!=(int *)(((caddr_t)dp)+sizeof(struct st))) *ip++ = 0; hp = &dp->s_hdr; hp->s_act = 0; hp->s_max = NSTCHQ; hp->s_first = hp->s_last = 0; if (dev < STNDSCH) { dp->s_flags = CH_OPEN; dp->s_ttyid = (unsigned) ( -(dev + 1)); dp->s_mode = STRAW; } else { dp->s_flags |= (CH_OPEN|CH_AVAIL); while(dp->s_flags & CH_AVAIL) sleep((caddr_t)dp,STMPRI); dp->s_mode = STRAW; } } spl0(); if ((dp->s_mode == 0) && (dev >= STNDSCH)) { u.u_error = ENXIO; return; } } stclose(dev) int dev; { register struct st *dp; register struct stbhdr *mp; extern struct stbhdr *getmsg(); dp = &st_st[dev]; spl5(); if (dp->s_rbuf) stfree((unsigned) stimap,dp->s_rbuf); while(mp = getmsg(&dp->s_hdr)) stfree((unsigned)stimap, mp); dp->s_flags = NULL; spl0(); } stwrite(dev) int dev; { register struct st *dp; register short unsigned loc; dp = &st_st[dev]; while ((loc=malloc(stomap,round(u.u_count))) == NULL) { stoflg++; sleep((caddr_t)stomap,STMPRI); } iomove(loc+stobuf,wrccnt=u.u_count,B_WRITE); while(putmsg(loc,wrccnt,wrccnt,dp) == NULL) { sthflg++; sleep((caddr_t)&sthflg,STMPRI); } } stread(dev) int dev; { register struct st *dp; register struct stbhdr *mp; extern struct stbhdr *getmsg(); unsigned n, cnt; dp = &st_st[dev]; spl5(); while(((dp->s_hdr).s_act==0)&&(dp->s_rbuf==NULL)) sleep((caddr_t)dp, STMPRI); spl0(); while((cnt=u.u_count) && u.u_error == 0) { if (dp->s_rbuf == NULL) if ((dp->s_rbuf = getmsg(&dp->s_hdr)) == NULL) return; else dp->s_roffset = 0; mp = dp->s_rbuf; iomove(mp->sm_loc + stibuf + dp->s_roffset, n=min(cnt,mp->sm_count - dp->s_roffset),B_READ); if (n == (mp->sm_count - dp->s_roffset)) { stfree((unsigned)stimap,mp); dp->s_rbuf = NULL; } else dp->s_roffset += n; continue; } } strxint(sel0,sel2,sel4) unsigned sel0, sel2; register struct stbhdr *sel4; { switch(sel2) { case RRTNXBUF: if (sel4->sm_type & FAIL) printf("stxmit fail\n"); stfree((unsigned)stomap,sel4); break; case RRTNEBUF: stfree((unsigned)stimap,sel4); break; case RRTNRBUF: strcvb(sel0); stinput(sel0,sel4); break; } } stioctl(dev,cmd,arg,mode) { register struct st *dp; struct set { char s_spa; char s_ssa; char typet; char s_dev; unsigned mode; } setbuff; register struct set *sp = &setbuff; extern struct stbhdr *stghdr(); register unsigned i; dp = &st_st[dev]; if (dev < STNDSCH) { if (copyin(arg,sp,sizeof setbuff)) { u.u_error = EFAULT; return; } dp->s_port = sp->s_dev; if (sp->mode) { vpmstop(sp->s_dev); stopflg |= (1 << (sp->s_dev & 07)); return; } for (i=STOBSZ; i; i>>=1) while (malloc(stomap,i)); for (i=STIBSZ; i; i>>=1) while (malloc(stimap,i)); sthdcnt = 0; stinithd(); mfree((unsigned)stomap,STOBSZ-sizeof(int),sizeof(int)); mfree((unsigned)stimap,STIBSZ-sizeof(int),sizeof(int)); stobase = (int)stobuf - (int)&_sdata; stibase = (int)stibuf - (int)&_sdata; if (u.u_error = vpmstart(sp->s_dev,STRM,strxint)) return; stopflg &= ~(1 << (sp->s_dev & 07)); strcvb((unsigned)sp->s_dev & 0377); } } stinput(sel0,mp) register struct stbhdr *mp; unsigned sel0; { register struct st *cp, *ap; struct st *ep; int sps; ap = cp = NULL; ep = &st_st[st_cnt]; sps = spl5(); if (mp->sm_type & FBLOCK) ttyid[sel0 & 07] = stid(mp); for(cp = &st_st[1]; cp != ep; cp++) { if(cp->s_ttyid == ttyid[sel0 & 07] && cp->s_port == sel0 && (cp->s_flags & (CH_OPEN | CH_AVAIL)) == CH_OPEN) break; if(!ap && cp->s_flags & CH_AVAIL) ap = cp; } if(cp != ep) { if(putmesgi(&cp->s_hdr, mp)) { if ((mp->sm_type & LBLOCK) || ((cp->s_hdr).s_max <= (cp->s_hdr).s_act)) wakeup((caddr_t)cp); splx(sps); return(NULL); } } else if(cp == ep && ap) { if(putmesgi(&ap->s_hdr, mp)) { ap->s_flags &= ~CH_AVAIL; ap->s_ttyid = ttyid[sel0 & 07]; ap->s_port = sel0; if ((mp->sm_type & LBLOCK) || ((ap->s_hdr).s_max <= (ap->s_hdr).s_act)) wakeup((caddr_t)ap); splx(sps); return(NULL); } } stfree((unsigned)stimap,mp); splx(sps); return(ENOSPC); } static putmsg(loc, size, count, cp) register struct st *cp; unsigned loc, size, count; { register struct stbhdr *dp; extern struct stbhdr *stghdr(); int sttemp; if((dp = stghdr()) == 0) return(NULL); sttemp = stobase + loc; dp->sm_locu = (sttemp>>16) & 03; dp->sm_locl = sttemp & 0177777; dp->sm_loc = loc; dp->sm_size = size; dp->sm_count = count; dp->sm_sta = (cp->s_ttyid >> 8) & 0377; dp->sm_dev = cp->s_ttyid & 0377; dp->sm_type = 0; vpmxmtq((unsigned) cp->s_port,dp); return(1); } static putmesgi(hdr,mp) register struct stmsghdr *hdr; register struct stbhdr *mp; { register struct stbhdr *mp2; if (hdr->s_act == hdr->s_max) { return(NULL); } hdr->s_act++; if (hdr->s_first == NULL) hdr->s_first = mp; if (mp2 = hdr->s_last) mp2->sm_nxt = mp; hdr->s_last = mp; return(1); } static struct stbhdr * getmsg(hdr) register struct stmsghdr *hdr; { register struct stbhdr *dp; if(hdr->s_act) { if (--hdr->s_act == 0) hdr->s_last = 0; dp = hdr->s_first; hdr->s_first = dp->sm_nxt; return(dp); } else return(NULL); } static stfree(map,mp) unsigned map; register struct stbhdr *mp; { register int sps; sps = spl5(); mfree(map,round(mp->sm_size),mp->sm_loc); stphdr(mp); if (stoflg) { stoflg = 0; wakeup((caddr_t)stomap); } splx(sps); } stinithd() { register struct stbhdr *bp; ffree = NULL; for (bp=sthdrb;bp < &sthdrb[STHBUF];bp++) stphdr(bp); } stphdr(bp) register struct stbhdr *bp; { register int sps; sps = spl5(); bp->sm_nxt = ffree; ffree = bp; sthdcnt++; if (sthflg) { sthflg = 0; wakeup((caddr_t) &sthflg); } splx(sps); return(0); } struct stbhdr * stghdr() { register struct stbhdr *bp; register int sps; sps = spl5(); if (ffree == NULL) { splx(sps); return(0); } bp = ffree; ffree = bp->sm_nxt; bp->sm_nxt = 0; sthdcnt--; splx(sps); return(bp); } strcvb(sel0) unsigned sel0; { unsigned mem; struct stbhdr *bp; int sttemp; if (stopflg & (1 << (sel0 & 07))) return; while(vpmemptq(sel0,(struct stbhdr *)0) < RCVLEN) { bp = NULL; if ((bp=stghdr()) && (mem=malloc(stimap,STMBSZ))) { bp->sm_count = bp->sm_size = STMBSZ; bp->sm_type = 0; sttemp = stibase + mem; bp->sm_locu = (sttemp>>16) & 03; bp->sm_locl = sttemp & 0177777; bp->sm_loc = mem; vpmemptq(sel0,bp); } else { if (bp) stphdr(bp); timeout(strcvb,sel0,60); break; } } }