# /* * add check to see if system is built right : if swap or root is on * aed, then.... */ /* * DA Converter Driver * * Modified 26Nov77 J.S.Kravitz to allow * * 1) Display list operation after particular stty call (eventuall, all will * be display list operation, but for the moment, this is compatible * with existing software.) * 2) Writes from multiple processes * 3) gtty returns various values, depending on last stty call * */ #include "/usr/sys/h/param.h" #include "/usr/sys/h/buf.h" #include "/usr/sys/h/conf.h" #include "/usr/sys/h/user.h" #include "/usr/sys/h/da.h" struct { char lo_byte; char hi_byte; }; struct devtab daadtab; /* aed device driver table */ struct buf dapbuf; /* for passing parameters between * write and strategy routines with help * from physio */ struct buf dabuf[2]; /* the buffer headers for ad and da; * two for double-buffering */ int dabufn; /* selects current dabuf */ #define DABSIZE 2560 /* buffer size */ #define DABLREC (2560/256) /* NOTE: NUMERATOR MUST = DABSIZE !!! * this is the number of disk blocks per record */ struct buf *daorgbp; /* will point to original buffer header */ char *daebn; /* block number of last block to be * transferred */ int daewc; /* word count for last transfer */ struct { int word; }; struct { int adds; int ader; int adcs; int adwc; int adba; int adca; int adda; }; #define ADADDR 0176710 struct /* global dec for the ad format structs */ { char *nblocks; int cyloff; } ad_sizes[8]; dastrategy(bufp) struct buf *bufp; { register struct buf *bp; register int ub; /* copy of u.u_base for getting * params out of user space */ register int ssplno; /* holds index of 1st desired sample * in 1st buffer, becomes virtual * address of same later */ char *t[4]; /* will hold params when we get them * from user space */ bp = bufp; /* get pointer to param buffer */ daorgbp = bp; /* remember for dastart's use later */ if ( (-bp->b_wcount) < ((DABSIZE * 2) + 4) ) /* user's buffer too small? */ { badpar: /* come here on bad param errors */ bp->b_flags =| B_ERROR; /* set buf's error bit */ bp->b_error = EINVAL; /* set error code */ iodone(bp); /* takes care of the rest */ return; /* we're all done */ } ub = u.u_base; /* get virtual address of user's write */ t[0] = fuword(ub); /* get 1st sample number (2 words) */ t[1] = fuword(ub =+ 2); t[2] = fuword(ub =+ 2); /* get last sample number (2 words) */ t[3] = fuword(ub =+ 2); ssplno = t[1].lo_byte & 0377; /* 1st sample # mod 256 * gives 1st sample # in 1st block */ dabuf[0].b_blkno = lshift(&t[0],-8); /* 1st sample # div 256 * gives 1st block # */ t[1] = lrem(dabuf[0].b_blkno,DABLREC); /* 1st block # mod blocks/rec * gives residue of 1st block * in 1st record */ dabuf[0].b_blkno =- t[1]; /* 1st block # - residue * gives block # of 1st record */ ssplno =+ (t[1] <<8); /* (1st sample # in 1st block) * +(block residue * 256) * gives 1st sample # in 1st record */ /* the following work similarly to the previous, but it * is the quantities for the last sample we are computing; * note that we compute a word count (negative). */ daewc = t[3].lo_byte & 0377; daebn = lshift(&t[2],-8); t[3] = lrem(daebn,DABLREC); daebn =- t[3]; daewc = -(daewc + (t[3] << 8) ); if ( daewc == 0 ) /* final word count = 0? */ { daewc = -DABSIZE; /* set to full buffer size */ daebn =- (DABLREC); /* decrease last block number by blocks per buffer */ } if (daebn <= dabuf[0].b_blkno) /* last block # <= first? */ goto badpar; /* process bad parameter */ dabuf[0].b_wcount = dabuf[1].b_wcount = -DABSIZE; /* word counts */ dabuf[0].b_dev = dabuf[1].b_dev = DAADDEV; /* devices */ dabuf[0].b_error = dabuf[1].b_error = 0; /* error codes */ dabuf[0].b_addr = bp->b_addr + 010; /* buffer addr (skip over params ) */ dabuf[0].b_xmem = bp->b_xmem; /* copy xmem bits */ if ( dabuf[0].b_addr < bp->b_addr ) /* did adding to addr overflow? */ { dabuf[0].b_xmem++; /* increment xmem bits */ } dabuf[0].b_flags = B_READ; /* set read bit */ dabuf[1].b_flags = B_READ; /* in both buffers */ dabuf[1].b_addr = dabuf[0].b_addr + (DABSIZE<<1); /* addr of 2nd buf is 1st + buffer size */ dabuf[1].b_xmem = dabuf[0].b_xmem; /* copy xmem bits */ if ( dabuf[1].b_addr < dabuf[0].b_addr ) /* did addr overflow? */ { dabuf[1].b_xmem++; /* increment xmem bits */ } DAADDR->dadrba = 0; /* clear ba overflow if any */ DAADDR->dadrst = ( DARSET1 | DARESET); /* reset attention */ daadstrategy(&dabuf[0]); /* start 1st disk transfer */ dabufn = 0; /* set buffer switch */ /* * reset done, diskwaiting and converter waiting flags */ dastate =& ~ ( DADONE | DAADWT | DACVWT ); iowait(&dabuf[0]); /* wait for 1st disk read */ dastate =| DAADLOCK; /* set ad lockout of other requests */ spl1(); /* let interrupts happen */ /* * wait until all aed requests are done, and then swipe * controller */ while ( (daadtab.d_active | daadtab.d_actf) != 0 ); dastate =| DAADISW | DASEEK; DAADDR->dadrst = DARESET; /* reset reset attention */ ub = u.u_base; /* set back to beg of buffer */ for ( ssplno =+ ub ; --ssplno >= ub ; ) /* loop thru virtual addresses of undesired samples in 1st buffer, if any */ suword(ssplno,0); /* set undesired samples to zero */ dabuf[1].b_blkno = dabuf[0].b_blkno + (DABLREC); /* block number for 2nd block */ dadskstart(&dabuf[1]); /* start read of 2nd block */ sleep (&dastate, PRIBIO); /* wait til done */ spl6(); /* no interrupts during dastart */ bp->b_flags =& ~B_DONE; /* reset done to avoid trouble */ dastart(); /* start conversion */ sleep (&dastate.hibyte, PRIBIO); /* wait til done */ iodone(bp); /* io is finished */ } dastart() { register struct buf *dabp, /* will point to buffer now going to converter */ *adbp; /* will point to buffer now going to disk */ if ( daorgbp->b_flags & B_DONE ) /* already done? */ return; if ( dastate & DADONE ) /* all done? */ { DAADDR->dadrst =& ~DAINTENB; /* shut off converter interrupts */ /* * restore disk interrupt handling to normal and re-enable * other's use of the disk */ dastate =& ~ (DAADISW | DAADLOCK); wakeup (&dastate.hibyte); /* wake waiters on it */ return; /* that's all */ } dabp = &dabuf[dabufn]; /* point to current buffer from disk */ DAADDR->dadrwc = dabp->b_wcount; /* set word count in interface */ DAADDR->dadrba = dabp->b_addr; /* set buffer address in interface */ /* * set interface status: extended mem bits, interrupt enable * reset attention, set go */ DAADDR->dadrst = ( (dabp->b_xmem << DAMEMSHIFT) & DAXMEM) | (DARESET | DAINTENB | DAGO) | ( (dastate & DASETSTEREO) ? DASTEREO:0); adbp = &dabuf[dabufn =^ 1]; /* point to other buffer */ /* next block number is previous + blocks per record; * is this <= last block number? */ if ( (adbp->b_blkno = dabp->b_blkno + (DABLREC)) <= daebn ) { if ( adbp->b_blkno == daebn ) /* last read? */ adbp->b_wcount = daewc; /* set word count */ adbp->b_flags = B_READ; /* set read */ dadskstart(adbp); /* start read */ } else /* block number > last block number */ { dastate =| DADONE; /* set done flag */ } } dadskstart(bp) struct buf *bp; { register char *p1, /* scratch for computations */ *p2; p1 = bp->b_blkno; /* get block # */ p2 = lrem(p1,10); /* sector */ p1 = ldiv(p1,10); /* cylinder and track */ ADADDR->adda = (p1 % 20) << 8 | p2; devstart(bp,&ADADDR->adca, ad_sizes[DAADDEV].cyloff +(p1/20),0); } daintr() { if ( dastate & DADONE ) /* all done? */ { dastart(); /* final processing */ return; } if ( DAADDR->dadrst < 0 ) /* error? */ { /* * no error bits set and buf addr = 0? */ if ( ( (DAADDR->dadrst & DAEBITS) | DAADDR->dadrba) == 0 ) { /* * reset error condition and re-init */ DAADDR->dadrba = 0; /* yes, 0 = 0, resets error */ DAADDR->dadrst = ((DAADDR->dadrst + DAINCMEM) & DAXMEM) | (DARESET | DAINTENB | DAGO); return; /* that's all */ } /* * set error bit in original request */ daorgbp->b_flags =| B_ERROR; dastate =| DADONE; /* set done flag */ dastart(); /* process done */ return; } if ( dastate & DAADWT ) /* disk waiting? */ { dastate =& ~ DAADWT; /* reset flag */ dastart(); /* start conversion */ } else /* last read not complete */ { dastate =| DACVWT; /* set converter waiting flag */ } } dadskint() { spl6(); /* lock out converter ints */ if ( dastate & DASEEK ) /* seeking 2nd block? */ { dastate =& ~ DASEEK; /* reset flag */ wakeup (&dastate); /* wake waiter */ return; } if ( dastate & DADONE ) /* all done? */ return; if ( ADADDR->adcs < 0 ) /* disk error? */ { daorgbp->b_flags =| B_ERROR; /* set error flag in buf */ dastate =| DADONE; /* set done flag */ dastart(); /* process done */ return; } if ( dastate & DACVWT ) /* converter waiting? */ { dastate =& ~ DACVWT; /* reset flag */ dastart(); /* and start converter */ } else { dastate =| DAADWT; /* else set disk wait flag */ } } dawrite(dev) { physio (dastrategy, &dapbuf, dev, B_WRITE); } dasgtty(dev,vec) int *vec; { register int *v; v = vec; if ( v != 0 ) /* gtty */ { switch (dastate & DARETMODES) { case DANORM: *v++ = DAADDR->dadrwc; *v++ = DAADDR->dadrba; *v++ = DAADDR->dadrst; return; case DARETSTATE: *v++ = 0; *v++ = 0; *v++ = 0; return; } } switch (u.u_arg[0]) { case 0: DAADDR->dadrst = u.u_arg[1]; return; case 1: /* * damn well better not be a transfer running now */ dastate = (dastate & ~DASETMODES) | (u.u_arg[1] & DASETMODES); return; } } daopen() { } daclose() { }