|  | @@ -372,3 +372,104 @@ static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  |  	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;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* s3c2410_dma_canload
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * work out if we can queue another buffer into the DMA engine
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (chan->load_state == S3C2410_DMALOAD_NONE ||
 | 
	
		
			
				|  |  | +	    chan->load_state == S3C2410_DMALOAD_1RUNNING)
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* s3c2410_dma_enqueue
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * queue an given buffer for dma transfer.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * id         the device driver's id information for this buffer
 | 
	
		
			
				|  |  | + * data       the physical address of the buffer data
 | 
	
		
			
				|  |  | + * size       the size of the buffer in bytes
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
 | 
	
		
			
				|  |  | + * is checked, and if set, the channel is started. If this flag isn't set,
 | 
	
		
			
				|  |  | + * then an error will be returned.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * It is possible to queue more than one DMA buffer onto a channel at
 | 
	
		
			
				|  |  | + * once, and the code will deal with the re-loading of the next buffer
 | 
	
		
			
				|  |  | + * when necessary.
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
 | 
	
		
			
				|  |  | +			dma_addr_t data, int size)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 | 
	
		
			
				|  |  | +	struct s3c2410_dma_buf *buf;
 | 
	
		
			
				|  |  | +	unsigned long flags;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan == NULL)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("%s: id=%p, data=%08x, size=%d\n",
 | 
	
		
			
				|  |  | +		 __func__, id, (unsigned int)data, size);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
 | 
	
		
			
				|  |  | +	if (buf == NULL) {
 | 
	
		
			
				|  |  | +		pr_debug("%s: out of memory (%ld alloc)\n",
 | 
	
		
			
				|  |  | +			 __func__, (long)sizeof(*buf));
 | 
	
		
			
				|  |  | +		return -ENOMEM;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	//pr_debug("%s: new buffer %p\n", __func__, buf);
 | 
	
		
			
				|  |  | +	//dbg_showchan(chan);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	buf->next  = NULL;
 | 
	
		
			
				|  |  | +	buf->data  = buf->ptr = data;
 | 
	
		
			
				|  |  | +	buf->size  = size;
 | 
	
		
			
				|  |  | +	buf->id    = id;
 | 
	
		
			
				|  |  | +	buf->magic = BUF_MAGIC;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	local_irq_save(flags);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (chan->curr == NULL) {
 | 
	
		
			
				|  |  | +		/* we've got nothing loaded... */
 | 
	
		
			
				|  |  | +		pr_debug("%s: buffer %p queued onto empty channel\n",
 | 
	
		
			
				|  |  | +			 __func__, buf);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		chan->curr = buf;
 | 
	
		
			
				|  |  | +		chan->end  = buf;
 | 
	
		
			
				|  |  | +		chan->next = NULL;
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
 | 
	
		
			
				|  |  | +			 chan->number, __func__, buf);
 | 
	
		
			
				|  |  | +
 |