# /* * TIU (DR11-B) interface to Spider */ #include "/sys/nsys/param.h" #include "/sys/nsys/conf.h" #include "/sys/nsys/user.h" #include "/sys/nsys/buf.h" #include "/sys/nsys/file.h" #include "/sys/nsys/reg.h" #define NCHAN 8 /* bits in tiuch flags */ #define T_WRITR 01 #define T_RAVL 02 #define T_ERROR 04 #define T_DONE 010 #define T_OPEN 020 #define T_EOF 040 /* drst bits */ #define T_TERROR 0100000 #define T_REJ 04000 #define T_IDLE 02000 /* drdb bits */ #define T_BKSTS 0100000 #define T_SLSTS 040000 #define T_WTSTS 010000 #define T_TROUB 02000 #define T_ODD 01000 #define T_SIGNL 0400 #define T_SELW 0200 #define TIUPRI 2 #define TIUADDR 172430 /* tiu command bits */ #define IENABLE 0100 #define GO 01 #define STOP 0 #define RCH 02 #define RDC 04 #define RNM 06 #define WSB 010 #define WCH 012 #define WDC 014 #define WDB 016 #define SREAD 1 #define SWRITE 2 #define SWSIG 3 #define SWDONE 4 struct { int drwc; int drba; int drst; int drdb; }; struct tiuch { char t_flags; char t_isig; char t_osig; char t_troub; char *t_buffer; }; struct tiuch tiu_dchan[NCHAN]; struct tiuch tiu_cchan[NCHAN]; struct { char lbyte; char hbyte; }; struct tiu { char t_state; char t_chan; char t_wflg; struct buf *t_actf; struct buf *t_actl; } tiu; tiuopen(dev, flag) { struct tiuch *cp; for (cp=tiu_dchan; cp < &tiu_dchan[NCHAN]; cp++) { if (cp->t_flags&T_OPEN || (cp+NCHAN)->t_flags&T_OPEN) continue; cp->t_flags = T_OPEN; cp->t_osig = 1; return; } u.u_error = ENXIO; } tiuclose() { } tiuwrite(dev) { int n, i, c; struct tiuch *cp; struct buf *bp; char *p; if ((cp = tiuchan(&i)) == NULL) return; spl5(); if (cp->t_flags&T_WRITR == 0) { while(tiubusy()) { tiu.t_wflg++; sleep(&tiu, TIUPRI); } stiuchan(i+0200); /* select W */ } spl0(); do { bp = getblk(NODEV); bp->b_flags = 0; p = bp->b_addr; for (n=0; n<512 && passc(&c) >= 0; n++) *p++ = c; if (u.u_count == 0 || u.u_error) bp->b_flags.hbyte = cp->t_osig; bp->b_wcount = n; bp->b_blkno = i; spl5(); while ((cp->t_flags&(T_WRITR|T_ERROR)) == 0) sleep(cp, TIUPRI); cp->t_flags =& ~T_DONE; tiustrategy(bp); while ((cp->t_flags&(T_DONE|T_ERROR)) == 0) sleep(bp, TIUPRI); spl0(); if (cp->t_flags&T_ERROR) u.u_error = EIO; brelse(bp); } while (u.u_count>0 && u.u_error==0); } tiuread(dev) { int i, n; char *p; struct tiuch *cp; struct buf *bp; if ((cp = tiuchan(&i)) == NULL) return; i = cp - tiu_dchan; do { if (bp = cp->t_buffer) { n = bp->b_wcount; p = bp->av_forw; } else { spl5(); while ((cp->t_flags&(T_RAVL|T_ERROR|T_EOF))==0) sleep(cp, TIUPRI); if (cp->t_flags&T_ERROR) goto rerr; if (cp->t_flags&T_EOF) return; bp = getblk(NODEV); bp->b_flags = B_READ; bp->b_blkno = i; cp->t_flags =& ~T_DONE; tiustrategy(bp); while ((cp->t_flags&(T_DONE|T_ERROR|T_EOF)) == 0) sleep(cp, TIUPRI); cp->t_isig = bp->b_flags.hbyte; if (cp->t_flags&T_ERROR) rerr: u.u_error = EIO; n = bp->b_wcount; p = bp->b_addr; spl0(); } if (cp->t_flags&T_EOF) { n = 0; u.u_count = 0; } while ((n--)>0 && cpass(*p++)>=0); if (n<=0 || u.u_error) { bp->b_flags = 0; brelse(bp); } else { bp->b_wcount = n; bp->av_forw = p; cp->t_buffer = bp; } } while (u.u_count && u.u_error==0); } tiustart() { struct buf *bp; if (tiubusy()) return; if ((bp = tiu.t_actf)==0) { if (tiu.t_wflg) { tiu.t_wflg = 0; wakeup(&tiu); } return; } stiuchan(bp->b_blkno); TIUADDR->drba = bp->b_addr; if (bp->b_flags&B_READ) { TIUADDR->drwc = -256; tiu.t_state = SREAD; TIUADDR->drst = IENABLE|RDC|GO; } else { tiu.t_state = SWRITE; if ((TIUADDR->drwc = -(bp->b_wcount>>1))==0) { tiuintr(); return; } TIUADDR->drst = IENABLE|WDC|GO; } } stiuchan(c) { if (c != tiu.t_chan) { tiu.t_chan = c&0177; if ((c&0177)>=NCHAN) c =+ 64-NCHAN; TIUADDR->drdb = c; TIUADDR->drst = IENABLE|WCH|GO; } } tiuintr() { struct buf *bp; struct tiuch *cp, *bcp; int i, s; if (TIUADDR->drst&(T_TERROR|T_REJ)) { tiuerr(-1, 2); return; } if (tiu.t_chan>=0) cp = &tiu_dchan[tiu.t_chan]; else cp = NULL; s = tiu.t_state; tiu.t_state = 0; if (s) { bp = tiu.t_actf; if (bp==NULL || cp==NULL) { tiuerr(-1, 0); return; } } if (TIUADDR->drdb&T_TROUB) { tiuerr(tiustop(), TIUADDR->drdb); goto done; } switch (s) { case SREAD: if (TIUADDR->drdb&T_SIGNL == 0) { tiuerr(tiustop(), 10); goto done; } s = 512 + (TIUADDR->drwc<<1); if ((TIUADDR->drst&T_ODD) == 0) s--; if ((bp->b_flags.hbyte = TIUADDR->drdb) != 0) cp->t_flags =& ~T_RAVL; goto done; case SWRITE: if (bp->b_wcount&01) { TIUADDR->drdb = bp->b_addr[bp->b_wcount-1]; TIUADDR->drst = IENABLE|WDB|GO; if ((TIUADDR->drst & T_IDLE)==0) { tiu.t_state = SWSIG; return; } } case SWSIG: cp->t_flags =& ~T_WRITR; TIUADDR->drdb = bp->b_flags.hbyte; TIUADDR->drst = IENABLE|WSB|GO; if ((TIUADDR->drst & T_IDLE)==0) { tiu.t_state = SWDONE; return; } done: case SWDONE: tiu.t_state = 0; tiu.t_actf = bp->av_forw; wakeup(cp); cp->t_flags =| T_DONE; default: if (TIUADDR->drdb&T_WTSTS && cp) cp->t_flags =| T_WRITR; while (TIUADDR->drdb&T_BKSTS) { TIUADDR->drst = IENABLE|RCH|GO; i = TIUADDR->drdb&0177; if (i>=64) i =+ NCHAN-64; if (i<0 || i >= 2*NCHAN) { i = 0; tiuerr(-1, 0); } bcp = &tiu_dchan[i]; if (s==0 || bcp != cp) bcp =| (TIUADDR->drdb&T_SELW)? T_RAVL:T_WRITR; wakeup(bcp); } tiustart(); } } tiustop() { register int lastchan; lastchan = tiu.t_chan; tiu.t_chan = -1; tiu.t_state = 0; TIUADDR->drst = IENABLE|STOP|GO; return(lastchan); } tiuerr(chan, code) { struct tiuch *cp; if (0>=chan && chan<2*NCHAN || (code&0177)>2) tiucherr(&tiu_dchan[chan], code); else { tiu.t_state = 0; tiu.t_actf = 0; wakeup(&tiu); for (cp = tiu_dchan; cp < &tiu_dchan[2*NCHAN]; cp++) tiucherr(cp, code); } } tiucherr(cp, code) struct tiuch *cp; { cp->t_flags =& ~(T_WRITR|T_RAVL); cp->t_flags =| T_ERROR|T_DONE; cp->t_troub = code; if (cp->t_buffer) { brelse(cp->t_buffer); cp->t_buffer = NULL; } wakeup(cp); } tiuchan(ip) int *ip; { register struct tiuch *cp; *ip = u.u_offset[1].hbyte; cp = &tiu_dchan[*ip]; if (cp->t_flags&(T_ERROR|T_EOF)) { if (cp->t_flags&T_ERROR) u.u_error = EIO; return(NULL); } return(cp); } tiubusy() { if (TIUADDR->drst&T_IDLE && TIUADDR->drdb&T_SLSTS) return(1); return(0); } tiustrategy(abp) struct buf *abp; { register struct buf *bp; bp = abp; bp->av_forw = NULL; if (tiu.t_actf==NULL) { tiu.t_actf = bp; tiustart(); } else tiu.t_actl->av_forw = bp; tiu.t_actl = bp; } snstat() { struct file *fp; struct tiu *cp; int op; op = fubyte(u.u_arg[1]); if ((fp=getf(u.u_ar0[R0]))==NULL) return; cp = &tiu_dchan[fp->f_offset[1].hbyte]; switch (op) { /* get signal byte */ case 0: cp->t_osig = fubyte(u.u_arg[0]); return; /* get signal byte */ case 1: subyte(u.u_arg[0], cp->t_isig); cp->t_isig = 0; return; /* get channel # */ case 2: op = fp->f_offset[1].hbyte; if (op>=NCHAN) op =+ 64-NCHAN; subyte(u.u_arg[0], op); return; /* get trouble code */ case 3: subyte(u.u_arg[0], cp->t_troub); cp->t_troub = 0; cp->t_flags =& ~T_ERROR; return; /* clear EOF request */ case 4: if (cp >= &tiu_dchan[NCHAN]) cp =- NCHAN; cp->t_flags =& ~T_EOF; return; /* set EOF request */ case 5: if (cp >= &tiu_dchan[NCHAN]) cp =- NCHAN; cp->t_flags =| T_EOF; return; /* open control channel */ case 6: if (cp < &tiu_dchan[NCHAN]) cp =+ NCHAN; if (cp->t_flags&T_OPEN) { u.u_error = EINVAL; return; } if ((fp = falloc())==NULL) return; cp->t_flags = T_OPEN; return; } u.u_error = EINVAL; }