/*
* issue pending() will start the next transfer
* - it only need be loaded here
* CAUTION the work queue function may run during the handler
* CAUTION function callbacks may have interesting side effects
*/
static irqreturn_t pl08x_irq(int irq, void *dev)
{
u32 mask = 0;
u32 reg;
unsigned long flags;
int c;
reg = readl(pd.base + PL08X_OS_ISR_ERR);
mb();
if (reg) {
/*
* An error interrupt (on one or more channels)
*/
dev_err(&pd.dmac->dev,
"%s - Error interrupt, register value 0x%08x\n",
__func__, reg);
/*
* Simply clear ALL PL08X error interrupts,
* regardless of channel and cause
*/
writel(0x000000FF, pd.base + PL08X_OS_ICLR_ERR);
}
reg = readl(pd.base + PL08X_OS_ISR);
mb();
for (c = 0; c < MAX_DMA_CHANNELS; c++) {
if ((1 << c) & reg) {
struct pl08x_txd *entry = NULL;
struct pl08x_txd *next;
spin_lock_irqsave(&pd.chanwrap[c]->lock, flags);
if (pd.chanwrap[c]->at) {
/*
* Update last completed
*/
pd.chanwrap[c]->lc =
(pd.chanwrap[c]->at->tx.cookie);
/*
* Callback peripheral driver for p/m
* to signal completion
*/
if (pd.chanwrap[c]->at->tx.callback) {
/*
* Pass channel number
*/
((struct pl08x_callback_param *)
pd.chanwrap[c]->at->tx.callback_param)->act = c;
pd.chanwrap[c]->at->tx.callback(
pd.chanwrap[c]->at->tx.callback_param);
}
/*
* Device callbacks should NOT clear
* the current transaction on the channel
*/
if (!pd.chanwrap[c]->at)
BUG();
/*
* Free the descriptor if it's not for a device
* using a circular buffer
*/
if (!(pd.chanwrap[c]->at->pcd->circular_buffer)) {
list_add_tail(&pd.chanwrap[c]->at->txd_list,
&pd.chanwrap[c]->release_list);
pd.chanwrap[c]->at = NULL;
if (pd.pool_ctr > PL08X_MAX_ALLOCS) {
schedule_work(&pd.dwork);
}
}
/*
* else descriptor for circular
* buffers only freed when
* client has disabled dma
*/
}
/*
* If descriptor queued, set it up
*/
if (!list_empty(&pd.chanwrap[c]->desc_list)) {
list_for_each_entry_safe(entry,
next, &pd.chanwrap[c]->desc_list, txd_list) {
list_del_init(&entry->txd_list);
pd.chanwrap[c]->at = entry;
break;
}
}
spin_unlock_irqrestore(&pd.chanwrap[c]->lock, flags);
mask |= (1 << c);
}
}
/*
* Clear only the terminal interrupts on channels we processed
*/
writel(mask, pd.base + PL08X_OS_ICLR_TC);
mb();
return mask ? IRQ_HANDLED : IRQ_NONE;
}
| 如果发现有任何错误,就退出 实际上此处很多种错误,而目前的此版本的驱动,暂时没加入更多的判断,仅仅是报错而已 |
| 此处,真正去调用你之前挂载的callback函数,在callback函数里面,常见要做的事情就是清除你设备的DMA enable位,然后调用complete去使得completion变量完成,使得你驱动得以继续执行 |