|
@@ -473,3 +473,107 @@ int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
|
|
|
pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
|
|
|
chan->number, __func__, buf);
|
|
|
|
|
|
+ if (chan->end == NULL) {
|
|
|
+ pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
|
|
|
+ chan->number, __func__, chan);
|
|
|
+ } else {
|
|
|
+ chan->end->next = buf;
|
|
|
+ chan->end = buf;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* if necessary, update the next buffer field */
|
|
|
+ if (chan->next == NULL)
|
|
|
+ chan->next = buf;
|
|
|
+
|
|
|
+ /* check to see if we can load a buffer */
|
|
|
+ if (chan->state == S3C2410_DMA_RUNNING) {
|
|
|
+ if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
|
|
|
+ if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
|
|
|
+ printk(KERN_ERR "dma%d: loadbuffer:"
|
|
|
+ "timeout loading buffer\n",
|
|
|
+ chan->number);
|
|
|
+ dbg_showchan(chan);
|
|
|
+ local_irq_restore(flags);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ while (s3c2410_dma_canload(chan) && chan->next != NULL) {
|
|
|
+ s3c2410_dma_loadbuffer(chan, chan->next);
|
|
|
+ }
|
|
|
+ } else if (chan->state == S3C2410_DMA_IDLE) {
|
|
|
+ if (chan->flags & S3C2410_DMAF_AUTOSTART) {
|
|
|
+ s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
|
|
|
+ S3C2410_DMAOP_START);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ local_irq_restore(flags);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(s3c2410_dma_enqueue);
|
|
|
+
|
|
|
+static inline void
|
|
|
+s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
|
|
|
+{
|
|
|
+ int magicok = (buf->magic == BUF_MAGIC);
|
|
|
+
|
|
|
+ buf->magic = -1;
|
|
|
+
|
|
|
+ if (magicok) {
|
|
|
+ kmem_cache_free(dma_kmem, buf);
|
|
|
+ } else {
|
|
|
+ printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* s3c2410_dma_lastxfer
|
|
|
+ *
|
|
|
+ * called when the system is out of buffers, to ensure that the channel
|
|
|
+ * is prepared for shutdown.
|
|
|
+*/
|
|
|
+
|
|
|
+static inline void
|
|
|
+s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
|
|
|
+{
|
|
|
+#if 0
|
|
|
+ pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
|
|
|
+ chan->number, chan->load_state);
|
|
|
+#endif
|
|
|
+
|
|
|
+ switch (chan->load_state) {
|
|
|
+ case S3C2410_DMALOAD_NONE:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case S3C2410_DMALOAD_1LOADED:
|
|
|
+ if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
|
|
|
+ /* flag error? */
|
|
|
+ printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
|
|
|
+ chan->number, __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case S3C2410_DMALOAD_1LOADED_1RUNNING:
|
|
|
+ /* I believe in this case we do not have anything to do
|
|
|
+ * until the next buffer comes along, and we turn off the
|
|
|
+ * reload */
|
|
|
+ return;
|
|
|
+
|
|
|
+ default:
|
|
|
+ pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
|
|
|
+ chan->number, chan->load_state);
|
|
|
+ return;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /* hopefully this'll shut the damned thing up after the transfer... */
|
|
|
+ dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#define dmadbg2(x...)
|
|
|
+
|
|
|
+static irqreturn_t
|