Kaynağa Gözat

waterHeterogeneousDataSynchronization memoryOperation.c 姚强 commit at 2020-11-03

姚强 4 yıl önce
ebeveyn
işleme
a0e6a2281b

+ 192 - 0
waterHeterogeneousDataSynchronization/dataSharedMemory/memoryOperation.c

@@ -577,3 +577,195 @@ s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
 #define dmadbg2(x...)
 
 static irqreturn_t
+s3c2410_dma_irq(int irq, void *devpw)
+{
+	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
+	struct s3c2410_dma_buf  *buf;
+
+	buf = chan->curr;
+
+	dbg_showchan(chan);
+
+	/* modify the channel state */
+
+	switch (chan->load_state) {
+	case S3C2410_DMALOAD_1RUNNING:
+		/* TODO - if we are running only one buffer, we probably
+		 * want to reload here, and then worry about the buffer
+		 * callback */
+
+		chan->load_state = S3C2410_DMALOAD_NONE;
+		break;
+
+	case S3C2410_DMALOAD_1LOADED:
+		/* iirc, we should go back to NONE loaded here, we
+		 * had a buffer, and it was never verified as being
+		 * loaded.
+		 */
+
+		chan->load_state = S3C2410_DMALOAD_NONE;
+		break;
+
+	case S3C2410_DMALOAD_1LOADED_1RUNNING:
+		/* we'll worry about checking to see if another buffer is
+		 * ready after we've called back the owner. This should
+		 * ensure we do not wait around too long for the DMA
+		 * engine to start the next transfer
+		 */
+
+		chan->load_state = S3C2410_DMALOAD_1LOADED;
+		break;
+
+	case S3C2410_DMALOAD_NONE:
+		printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
+		       chan->number);
+		break;
+
+	default:
+		printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
+		       chan->number, chan->load_state);
+		break;
+	}
+
+	if (buf != NULL) {
+		/* update the chain to make sure that if we load any more
+		 * buffers when we call the callback function, things should
+		 * work properly */
+
+		chan->curr = buf->next;
+		buf->next  = NULL;
+
+		if (buf->magic != BUF_MAGIC) {
+			printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
+			       chan->number, __func__, buf);
+			return IRQ_HANDLED;
+		}
+
+		s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
+
+		/* free resouces */
+		s3c2410_dma_freebuf(buf);
+	} else {
+	}
+
+	/* only reload if the channel is still running... our buffer done
+	 * routine may have altered the state by requesting the dma channel
+	 * to stop or shutdown... */
+
+	/* todo: check that when the channel is shut-down from inside this
+	 * function, we cope with unsetting reload, etc */
+
+	if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
+		unsigned long flags;
+
+		switch (chan->load_state) {
+		case S3C2410_DMALOAD_1RUNNING:
+			/* don't need to do anything for this state */
+			break;
+
+		case S3C2410_DMALOAD_NONE:
+			/* can load buffer immediately */
+			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 IRQ_HANDLED;
+			}
+
+			break;
+
+		case S3C2410_DMALOAD_1LOADED_1RUNNING:
+			goto no_load;
+
+		default:
+			printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
+			       chan->number, chan->load_state);
+			return IRQ_HANDLED;
+		}
+
+		local_irq_save(flags);
+		s3c2410_dma_loadbuffer(chan, chan->next);
+		local_irq_restore(flags);
+	} else {
+		s3c2410_dma_lastxfer(chan);
+
+		/* see if we can stop this channel.. */
+		if (chan->load_state == S3C2410_DMALOAD_NONE) {
+			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
+				 chan->number, jiffies);
+			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
+					 S3C2410_DMAOP_STOP);
+		}
+	}
+
+ no_load:
+	return IRQ_HANDLED;
+}
+
+static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
+
+/* s3c2410_request_dma
+ *
+ * get control of an dma channel
+*/
+
+int s3c2410_dma_request(enum dma_ch channel,
+			struct s3c2410_dma_client *client,
+			void *dev)
+{
+	struct s3c2410_dma_chan *chan;
+	unsigned long flags;
+	int err;
+
+	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
+		 channel, client->name, dev);
+
+	local_irq_save(flags);
+
+	chan = s3c2410_dma_map_channel(channel);
+	if (chan == NULL) {
+		local_irq_restore(flags);
+		return -EBUSY;
+	}
+
+	dbg_showchan(chan);
+
+	chan->client = client;
+	chan->in_use = 1;
+
+	if (!chan->irq_claimed) {
+		pr_debug("dma%d: %s : requesting irq %d\n",
+			 channel, __func__, chan->irq);
+
+		chan->irq_claimed = 1;
+		local_irq_restore(flags);
+
+		err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
+				  client->name, (void *)chan);
+
+		local_irq_save(flags);
+
+		if (err) {
+			chan->in_use = 0;
+			chan->irq_claimed = 0;
+			local_irq_restore(flags);
+
+			printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
+			       client->name, chan->irq, chan->number);
+			return err;
+		}
+
+		chan->irq_enabled = 1;
+	}
+
+	local_irq_restore(flags);
+
+	/* need to setup */
+
+	pr_debug("%s: channel initialised, %p\n", __func__, chan);
+
+	return chan->number | DMACH_LOW_LEVEL;
+}