⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pdma_ds5000.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 3 页
字号:
	pd->targcnt += pd->pb_count[ active ];	/* update target count */	pd->pb_flags[ active ] = PB_FINISHED;        /* If there is still more data that will be transfered setup the old	active buffer for the next interrupt. */	if( (pd->count - pd->usercnt) != 0 )	/* still more data */	{	    /* Setup the count for the PDMA transfer. */	    lcount = XFER_BUFCNT( pd->count - pd->usercnt );	/* how much */	    pd->pb_count[ active ] = lcount;	    pd->usercnt += lcount;		/* update count for later */	    pd->pb_flags[ active ] = PB_READY;	/* set to ready for data */	    PRINTD(targid, 0x8000,	    ("ds5000_cont: (READ) more data, new pb_count = %x, usercnt = %x\n",		lcount, pd->usercnt));	}    } /* end of (pd->iodir == SZ_DMA_READ) */    else    {        /* If the operation is a DMA_OUT: the next buffer has valid data in it        ready for the SCSI chip to access.  The DMA is started on the next	buffer. The "active" buffer, which is now CPU_ACTIVE, is filled 	if there is still more data to be moved from user space. */        /* Load up the SCSI chip with the address and count for the next	buffer. */	/* Load addr reg, set the write direction bit. */	ascar->rambuf_dma =	    (DMA_ASC_WRITE | (pd->pb_offset[ next ] & 0x00ffffff));	wbflush();	ASC_LOADCNTR(ascaddr, pd->pb_count[ next ]);	/* load counter */	wbflush();        /* Start the DMA operation in the ASC. */	sc->sc_asccmd = pd->opcode;   	ascaddr->asc_cmd = pd->opcode;	wbflush();				/* clear write buffer */        /* Set the flag to inform the driver that DMA is in progress. */	pd->pb_flags[ next ] = PB_DMA_ACTIVE;	sc->sc_szflags[ targid ] |= SZ_DID_DMA;        /* Update the target side counter.  The data has been moved to the	target from the RAM buffer. */	pd->targcnt +=  pd->pb_count[ active ]; /* update target count */        /* Switch the "active" pipe buffer from DMA_ACTIVE to CPU_ACTIVE, the	SCSI chip is done with it. */	pd->pb_flags[ active ] = PB_CPU_ACTIVE;        /* Check the count value, if there is more data to be preloaded into	the now CPU_ACTIVE "active" buffer move it in and set the flags. */	if( (pd->count - pd->usercnt) != 0 )		/* still more data */	{	    /* Setup the count for the PDMA transfer. */            int len;	    len = lcount = XFER_BUFCNT( pd->count - pd->usercnt );	    if( (pd->usercnt + lcount) > sc->sc_b_bcount[targid] )  {	        /* Calc the new len to the end. */	        len = sc->sc_b_bcount[targid] - pd->usercnt;	        /* Zero out the half of the RAM buffer, this will deal with	           the zero fill requirement. */	        (*sc->dma_bzero)		   ( sc->pdma_rambuff + RAM_ADJUST(sc, pd->pb_offset[active]),		    lcount); 	        wbflush();	  }	  /* Move the data to write into the RAM buffer. */	  (*sc->dma_wbcopy)( (pd->data_addr + pd->usercnt),		(sc->pdma_rambuff + RAM_ADJUST(sc, pd->pb_offset[active])),		len);	  wbflush();	  pd->usercnt += lcount;		/* update user count */	  pd->pb_count[ active ] = lcount;	  pd->pb_flags[ active ] = PB_LOADED;	    	}	else	{	    pd->pb_flags[ active ] = PB_FINISHED;	}    } /* end of else on (pd->iodir == SZ_DMA_READ) */    return( pd->targcnt );	/* return current progress */}/************************************************************************int pdma_end( sc, targid )Inputs:	sz_softc *sc;		 pointer to the softc structure 	int targid;		 current targit ID Function:	Handle the completion of the DMA operation.  Free up the necessary	DMA resources that were allocated in dma_setup().  Handle the final	move of the data to user space if the operation was a read.Return:	The number of bytes transfered over the entire DMA operation.**************************************************************************/intds5000_end( sc, targid )    struct sz_softc *sc;	/* pointer to the softc structure */    int targid;			/* current targit ID */{    PDMA *pd;			/* pointer for the DMA control struct */    ASC_REG *ascaddr; 		/* pointer for the SCSI chip registers */    int	ffr;			/* value for the FIFO flags */    int	tcount;			/* corrected count for the ASC counters */    int lcount;			/* local count from the transfers */    int active;			/* index for the current active pipe buffer */    int next;			/* index for the next pipe buffer */    int i;			/* buffer loop counter */    int len;    PRINTD( targid, 0x1,	("ds5000_end entry sc:%x targ:%d\n", sc, targid));    pd = &sc->pdma_ctrl[ targid ];	/* assign the pointer */    ascaddr = (ASCREG *)sc->sc_scsiaddr;/* get the chip addr */    /* Find the current active buffer in the pipe.  The offset and counts are    needed.  The return value will not be checked. */    get_bindex( pd, &active, &next );	/* scan the buffers for DMA_ACTIVE */    /* From the active buffers count and the SCSI chips actual xfer counter    register value, calc how much data was transfered.  Update the working    counter(s) for the return xfer count.  So far the SCSI chip counters    are all down counters, making the xfer count calc a simple subtaction.    The counters in the ASC have to be corrected for the # of bytes    left in the FIFO but not transferred when the target changed phase. */    ffr =  (int)ascaddr->asc_ffss;	/* get the fifo flags count */    ffr &= ASC_FIFO_MSK;		/* mask off sequ step bits */    ASC_GETCNTR(ascaddr, tcount);	/* get the counter value */    ASC_LOADCNTR(ascaddr, 0);		/* JAG - force TC bit off */    wbflush();     if ((tcount != 0) || (ffr != 0)) {	  PRINTD(targid, 0x8000, ("ds5000_end: ffr = 0x%x\n", ffr));    }    tcount += ffr;			/* update count by whats in FIFO */    lcount = pd->pb_count[ active ] - tcount;    /* keep track of total number of bytes actually transferred */    sc->sc_ascdmacount[targid] += lcount;    /* If the last operation was a SZ_DMA_READ, move the data to user space. */    if( pd->iodir == SZ_DMA_READ )    {      /* Switch the pipe buffer from DMA_ACTIVE to CPU_ACTIVE, the SCSI	chip is done with it. */	pd->pb_flags[ active ] = PB_CPU_ACTIVE;	PRINTD(targid, 0x8000, ("ds5000_end: (READ) bcopy %x bytes\n", lcount));        /* Move the READ data to user space. */	if( lcount != 0 )		/* don't bother if no data */	{	    len = lcount;	    /* Make sure we don't go beyond user's buffer */            if( sc->sc_ascdmacount[targid] > sc->sc_b_bcount[targid] )  {	         len = lcount - 			(sc->sc_ascdmacount[targid] - sc->sc_b_bcount[targid]);	    }	    (*sc->dma_rbcopy)		/* move to user space */		((sc->pdma_rambuff + RAM_ADJUST( sc, pd->pb_offset[ active ] )),		(pd->data_addr + pd->targcnt), len);	    wbflush();	}    }    /* Update the target count, the data has moved between the RAM buffer and    target. */    pd->targcnt += lcount;		/* update working count */    /* Clean up after ourselves.  Deallocate the pipe [for dynamic alloc].  Set    all the flags to finished.  Clear the SZ_DID_DMA flag. [What else ?] */    sc->sc_szflags[ targid ] &= ~SZ_DID_DMA;	/* DID_DMA is done */    for( i = 0; i < PIPE_BUF_NUM; i++ )    {	pd->pb_flags[i] = PB_FINISHED;		/* just for completion */    }    pd->pstate = PDMA_IDLE;			/* all done */    /* Return the accumulated working count to the driver.  No checking has    been done to verify that all the data has been transfered. */    return( pd->targcnt );}/************************************************************************/* Support routines. *//************************************************************************/* This routine will return through the "active/next" pointers theindex of the pipe buffers that are currently "active" and which one is"next".  The currently active buffer will have the PB_DMA_ACTIVE flagset in it's flags field.  The "next" buffer will be the next buffer inline.  There will be no checking on the state of the "next" buffer,this routine can be called for a DMA_IN or DMA_OUT phase.  This routineis very tightly bound to the number of buffers in the pipe.  At thistime the implementation is based on 2, PIPE_BUF_NUM, buffers per pipe.If the number of buffers per pipe changes this routine will have tochange to reflect the change.    NOTE: one possible idea for multiple buffers is to find the first    one that has PB_DMA_ACTIVE and for the next index increment to the    following buffer checking for wrap around.**************************************************************************/int get_bindex( pd, active, next )    PDMA *pd;			/* ptr for the control structure */    int *active;		/* holder for the active index */    int *next;			/* holder for the active index */{  /* Find the current active buffer in the pipe.  The offset and counts are    needed.  A cascadding if/else sequence is used here, there is no reason    why there cannot be more than 2 buffers w/in the pipe.  For just 2 buffers    this quick. */    if( pd->pb_flags[0] == PB_DMA_ACTIVE )    {	*active = 0;	*next = 1;    }    else if( pd->pb_flags[1] = PB_DMA_ACTIVE )    {	*active = 1;	*next = 0;    }    else    {	*active = 0;			/* default error fall through */	*next = 1;	return( PDMA_FAIL );		/* just in case */    }    return( PDMA_SUCCESS );		/* all done and selected */ }/************************************************************************/intds5000_flush( sc, targid )    struct sz_softc *sc;	/* pointer to the softc structure */    int targid;			/* current targit ID */{    PDMA *pd;			/* pointer for the DMA control struct */    int i;			/* buffer loop counter */    PRINTD( targid, 0x1,	("ds5000_flush entry sc:%x targ:%d\n", sc, targid));    pd = &sc->pdma_ctrl[ targid ];	/* assign the pointer */    for( i = 0; i < PIPE_BUF_NUM; i++ )    {      /* Flush, or zero out the pipe buffer. */	(*sc->dma_bzero)	    ( sc->pdma_rambuff + RAM_ADJUST(sc, pd->pb_offset[i]),	    MAX_XFER_SIZE );	wbflush();    }    return( PDMA_SUCCESS );		/* all done */ }/************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -