|
@@ -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);
|
|
|
+
|