|  | @@ -829,3 +829,146 @@ EXPORT_SYMBOL(s3c2410_dma_free);
 | 
	
		
			
				|  |  |  static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	unsigned long flags;
 | 
	
		
			
				|  |  | +	unsigned long tmp;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s:\n", __func__);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dbg_showchan(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_save(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	s3c2410_dma_call_op(chan,  S3C2410_DMAOP_STOP);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
 | 
	
		
			
				|  |  | +	tmp |= S3C2410_DMASKTRIG_STOP;
 | 
	
		
			
				|  |  | +	//tmp &= ~S3C2410_DMASKTRIG_ON;
 | 
	
		
			
				|  |  | +	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if 0
 | 
	
		
			
				|  |  | +	/* should also clear interrupts, according to WinCE BSP */
 | 
	
		
			
				|  |  | +	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
 | 
	
		
			
				|  |  | +	tmp |= S3C2410_DCON_NORELOAD;
 | 
	
		
			
				|  |  | +	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* should stop do this, or should we wait for flush? */
 | 
	
		
			
				|  |  | +	chan->state      = S3C2410_DMA_IDLE;
 | 
	
		
			
				|  |  | +	chan->load_state = S3C2410_DMALOAD_NONE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_restore(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	unsigned long tmp;
 | 
	
		
			
				|  |  | +	unsigned int timeout = 0x10000;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	while (timeout-- > 0) {
 | 
	
		
			
				|  |  | +		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (!(tmp & S3C2410_DMASKTRIG_ON))
 | 
	
		
			
				|  |  | +			return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("dma%d: failed to stop?\n", chan->number);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* s3c2410_dma_flush
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * stop the channel, and remove all current and pending transfers
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c2410_dma_buf *buf, *next;
 | 
	
		
			
				|  |  | +	unsigned long flags;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dbg_showchan(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_save(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan->state != S3C2410_DMA_IDLE) {
 | 
	
		
			
				|  |  | +		pr_debug("%s: stopping channel...\n", __func__ );
 | 
	
		
			
				|  |  | +		s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	buf = chan->curr;
 | 
	
		
			
				|  |  | +	if (buf == NULL)
 | 
	
		
			
				|  |  | +		buf = chan->next;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	chan->curr = chan->next = chan->end = NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (buf != NULL) {
 | 
	
		
			
				|  |  | +		for ( ; buf != NULL; buf = next) {
 | 
	
		
			
				|  |  | +			next = buf->next;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			pr_debug("%s: free buffer %p, next %p\n",
 | 
	
		
			
				|  |  | +			       __func__, buf, buf->next);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
 | 
	
		
			
				|  |  | +			s3c2410_dma_freebuf(buf);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dbg_showregs(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	s3c2410_dma_waitforstop(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if 0
 | 
	
		
			
				|  |  | +	/* should also clear interrupts, according to WinCE BSP */
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		unsigned long tmp;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
 | 
	
		
			
				|  |  | +		tmp |= S3C2410_DCON_NORELOAD;
 | 
	
		
			
				|  |  | +		dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dbg_showregs(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_restore(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	unsigned long flags;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_save(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dbg_showchan(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* if we've only loaded one buffer onto the channel, then chec
 | 
	
		
			
				|  |  | +	 * to see if we have another, and if so, try and load it so when
 | 
	
		
			
				|  |  | +	 * the first buffer is finished, the new one will be loaded onto
 | 
	
		
			
				|  |  | +	 * the channel */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan->next != NULL) {
 | 
	
		
			
				|  |  | +		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
 | 
	
		
			
				|  |  | +				pr_debug("%s: buff not yet loaded, no more todo\n",
 | 
	
		
			
				|  |  | +					 __func__);
 | 
	
		
			
				|  |  | +			} else {
 | 
	
		
			
				|  |  | +				chan->load_state = S3C2410_DMALOAD_1RUNNING;
 | 
	
		
			
				|  |  | +				s3c2410_dma_loadbuffer(chan, chan->next);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
 | 
	
		
			
				|  |  | +			s3c2410_dma_loadbuffer(chan, chan->next);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_restore(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 |