Linux驅動修煉之道-DMA框架原始碼分析(下)
阿新 • • 發佈:2019-02-06
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; //當前傳輸完畢的buf
dbg_showchan(chan);
/* modify the channel state */
switch (chan->load_state) { //改變狀態,如果對上邊那4個狀態理解了很容易看懂的
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
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); //buf傳輸完成後的操作
/* free resouces */
s3c2410_dma_freebuf(buf); //釋放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) { //還有要傳輸的buf,則繼續傳輸
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); //載入buf
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, //停止DMA傳輸
S3C2410_DMAOP_STOP);
}
}
no_load:
return IRQ_HANDLED;
}