# /* */ /* * TIU (DR11-B) interface to Spider */ #include "../../h/param.h" #include "../../h/conf.h" #include "../../h/user.h" #include "../../h/buf.h" #include "../../h/reg.h" #include "../../h/inode.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 #define T_STOP 0100 #define T_WRITW 0200 /* drst bits */ #define T_TERROR 0100000 #define T_REJ 04000 #define T_IDLE 02000 #define T_SON 01000 /* 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 (-1) #define TIULPRI 1 #define TIUADDR 0172430 /* 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 #define SSTOP 5 #define SSEL 6 #define TIMLIM 5 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 tiu { char t_state; char t_chan; char t_time; char t_timo; char t_nopen; struct buf *t_actf; struct buf *t_actl; } tiu; tiuopen(dev, flag) { int tiutimeout(); register struct tiuch *cp; register struct buf *bp; if ((cp = tiuptr(dev)) == NULL) { u.u_error = ENXIO; return; } if (cp->t_flags&T_OPEN) { u.u_error = EBUSY; return; } cp->t_flags = T_OPEN; cp->t_osig = 1; if (tiu.t_nopen++ == 0) { tiu.t_chan = -1; timeout(tiutimeout, 0, HZ); } cp->t_flags =| T_STOP; tiustart(); } tiuclose(dev) { register struct tiuch *cp; if ((cp = tiuptr(dev)) == 0) return; cp->t_flags =| T_STOP; tiustart(); cp->t_flags =& T_STOP; tiu.t_nopen --; } tiuwrite(dev) { register int n; register struct tiuch *cp; register struct buf *bp; if ((cp = tiuchan(dev)) == NULL) return; do { spl5(); if ((cp->t_flags&T_WRITR) == 0) { cp->t_flags =| T_WRITW; /* want select W */ tiustart(); } while ((cp->t_flags&(T_WRITR|T_ERROR|T_EOF)) == 0) sleep(cp, TIULPRI); spl0(); if (tiucheck(cp)) return; bp = getblk(NODEV); if (n = min(512, u.u_count)) iomove(bp, 0, n, B_WRITE); if (u.u_count == 0 || u.u_error) bp->b_blkno = cp->t_osig; else bp->b_blkno = 0; bp->b_dev.d_minor = dev.d_minor; bp->b_wcount = n; bp->b_flags = B_WRITE; spl5(); cp->t_flags =& ~T_DONE; tiustrategy(bp); while ((cp->t_flags&(T_DONE|T_ERROR|T_EOF)) == 0) sleep(cp, TIUPRI); spl0(); brelse(bp); if (tiucheck(cp)) return; } while (u.u_count); } tiuread(dev) { register int n; register struct tiuch *cp; register struct buf *bp; if ((cp = tiuchan(dev)) == NULL) return; spl5(); while ((cp->t_flags&(T_RAVL|T_ERROR|T_EOF))==0) sleep(cp, TIULPRI); spl0(); if (tiucheck(cp)) return; bp = getblk(NODEV); bp->b_flags = B_READ; bp->b_dev.d_minor = dev.d_minor; cp->t_flags =& ~T_DONE; tiustrategy(bp); while ((cp->t_flags&(T_DONE|T_ERROR|T_EOF)) == 0) sleep(cp, TIUPRI); spl0(); if (cp->t_isig = bp->b_blkno) cp->t_flags =& ~T_RAVL; if (tiucheck(cp) == 0) { if (n = min(bp->b_wcount, u.u_count)) iomove(bp, 0, n, B_READ); } brelse(bp); } tiucheck(acp) struct tiuch *acp; { register struct tiuch *cp; cp = acp; if (cp->t_flags & (T_EOF | T_ERROR)) { if (cp->t_flags&T_ERROR) u.u_error = EIO; return(1); } return(0); } tiustart() { register struct buf *bp; register i; if (tiu.t_state) return; for (i=0; ib_dev.d_minor) == 0) return; TIUADDR->drba = bp->b_addr; if (bp->b_flags&B_READ) { TIUADDR->drwc = -257; 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; } tiu.t_time = TIMLIM; } tiucntrl(chan, acp) struct tiuch *acp; { register struct tiu *cp; cp = acp; if (cp->t_flags&T_STOP) { if (stiuchan(chan+0400)) { cp->t_flags =& ~T_STOP; tiu.t_state = SSTOP; tiu.t_time = TIMLIM; } return(1); } if (cp->t_flags&T_WRITW) { if (stiuchan(chan+0200)) { cp->t_flags =& ~T_WRITW; tiu.t_time = TIMLIM; } return(1); } return(0); } stiuchan(ac) { register int c; c = ac; if (c != tiu.t_chan) { if ((TIUADDR->drst&T_IDLE)==0 || (TIUADDR->drdb&T_SLSTS)==0) { tiu.t_state = SSEL; tiu.t_time = TIMLIM; return(0); } tiu.t_chan = c&0177; TIUADDR->drdb = c; TIUADDR->drst = IENABLE|WCH|GO; } return(1); } tiutimeout() { tiu.t_time--; if (tiu.t_time == 0) { tiu.t_timo++; tiuintr(); } else if (tiu.t_time < 0) tiu.t_time = 0; if (tiu.t_nopen) timeout(tiutimeout, 0, HZ); } tiuintr() { register struct buf *bp; register struct tiuch *cp; struct tiuch *lastcp; register int s; s = tiu.t_state; if ((s==SSTOP || s==SSEL) && tiu.t_timo==0 && ((TIUADDR->drst&T_IDLE)==0 || (TIUADDR->drdb&T_SLSTS)==0)) return; tiu.t_time = 0; cp = tiuptr(tiu.t_chan); tiu.t_state = 0; bp = NULL; if (s && s!=SSTOP && s!=SSEL) { bp = tiu.t_actf; if (bp==NULL || cp==NULL) { tiuerr(-1, 0); goto done; } } if ((TIUADDR->drst&(T_TERROR|T_REJ)) || tiu.t_timo) { tiuerr(tiustop(), 040+s+040*(tiu.t_timo!=0)); goto done; } if (TIUADDR->drdb&T_TROUB) { tiuerr(tiustop(), TIUADDR->drdb); goto done; } switch (s) { case SSTOP: tiustop(); goto done; case SREAD: if ((TIUADDR->drdb&T_SIGNL) == 0) { tiuerr(tiustop(), 10); goto done; } s = 513 + (TIUADDR->drwc<<1); if ((TIUADDR->drdb&T_ODD) != 0) s++; bp->b_wcount = s; bp->b_blkno = (TIUADDR->drdb).lobyte; s = SREAD; 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; tiu.t_time = TIMLIM; return; } } case SWSIG: cp->t_flags =& ~T_WRITR; TIUADDR->drdb = bp->b_blkno; TIUADDR->drst = IENABLE|WSB|GO; if ((TIUADDR->drst & T_IDLE)==0) { tiu.t_state = SWDONE; tiu.t_time = TIMLIM; return; } done: case SWDONE: case SSEL: if (bp && tiu.t_actf) tiu.t_actf = bp->av_forw; if (cp) { wakeup(cp); cp->t_flags =| T_DONE; } default: if (TIUADDR->drdb&T_WTSTS && cp) { cp->t_flags =| T_WRITR; wakeup(cp); } lastcp = cp; while (TIUADDR->drdb&T_BKSTS) { TIUADDR->drst = IENABLE|RCH|GO; if ((cp = tiuptr(TIUADDR->drdb)) == NULL) tiuerr(-1, 0); else if (s==0 || lastcp != cp) { cp->t_flags =| (TIUADDR->drdb&T_SELW)!=0? T_RAVL:T_WRITR; wakeup(cp); } } 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, acode) { register struct tiuch *cp; register code; tiu.t_timo = 0; code = acode; if ((cp = tiuptr(chan)) != NULL) tiucherr(cp, code); else { tiu.t_state = 0; tiu.t_actf = 0; for (cp = tiu_dchan; cp < &tiu_dchan[2*NCHAN]; cp++) tiucherr(cp, code); } } tiucherr(acp, code) struct tiuch *acp; { register struct tiuch *cp; cp = acp; cp->t_flags =& ~(T_WRITR|T_RAVL); cp->t_flags =| T_ERROR|T_DONE; cp->t_troub = code; wakeup(cp); } tiuchan(dev) { register struct tiuch *cp; if ((cp = tiuptr(dev)) == NULL) { u.u_error = ENXIO; return(NULL); } if (cp->t_flags&(T_ERROR|T_EOF)) { if (cp->t_flags&T_ERROR) u.u_error = EIO; return(NULL); } return(cp); } 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(dev, v) { register struct tiu *cp; register int channo; channo = dev.d_minor; if ((cp = tiuptr(channo))==NULL) return; switch (u.u_arg[1]) { /* set signal byte */ case 0: cp->t_osig = fubyte(u.u_arg[0]); return; /* get signal byte */ case 1: suword(u.u_arg[0], cp->t_isig); cp->t_isig = 0; return; /* get channel # */ case 2: suword(u.u_arg[0], channo); return; /* get trouble code */ case 3: suword(u.u_arg[0], cp->t_troub); cp->t_troub = 0; cp->t_flags =& ~T_ERROR; return; /* clear EOF request */ case 4: if (channo >= 64) cp = tiuptr(channo - 64); cp->t_flags =& ~T_EOF; return; /* set EOF request */ case 5: if (channo >= 64) cp = tiuptr(channo - 64); cp->t_flags =| T_EOF; wakeup(cp); return; } u.u_error = EINVAL; } tiuptr(dev) { register struct tiuch *cp; register int d; d = dev.d_minor & 0177; if (d=64 && d