驱动申请中断API
request_irq
框架流程图如下所示:
具体流程如下所示;
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
/*
/**
* request_threaded_irq - allocate an interrupt line
* @irq: Interrupt line to allocate
* @handler: Function to be called when the IRQ occurs.
* Primary handler for threaded interrupts
* If NULL and thread_fn != NULL the default
* primary handler is installed
* @thread_fn: Function called from the irq handler thread
* If NULL, no irq thread is created
* @irqflags: Interrupt type flags
* @devname: An ascii name for the claiming device
* @dev_id: A cookie passed back to the handler function
*/
struct irq_desc *desc;
desc = irq_to_desc(irq);
a.通过 virq 获取对应中断描述符 ,以 virq 为索引,通过 radix tree 中搜索获取对应irq_desc;
struct irqaction *action;
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;
retval = irq_chip_pm_get(&desc->irq_data);/* 通过 chip 对irq chip的上电操作???*/
retval = __setup_irq(irq, desc, action);/* 注册 */
b.分配 struct irqaction,赋值,调用 __setup_irq 进行实际的注册过程,把该 action填充到 desc中;
c.接下来解剖注册函数的实现方式:__setup_irq
init_waitqueue_head(&desc->wait_for_threads);
1).初始化一个等待队列,这个等待队列包含在中断描述符中
ret = __irq_set_trigger(desc,new->flags & IRQF_TRIGGER_MASK);
2).根据传递进来的参数设置中断触发,类型,比如在 FP中,触发类型为上升沿触发;
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
3).清除中断
irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
irq_enable(desc);/*使能中断*/
4).使能中断
register_irq_proc(irq, desc);
irq_add_debugfs_entry(irq, desc);
new->dir = NULL;
register_handler_proc(irq, new);
d.创建 proc系统下相关节点,方便调试;
free_irq
代码流程如下所示,
const void *free_irq(unsigned int irq, void *dev_id)
struct irq_desc *desc = irq_to_desc(irq);/* radix tree 方式获取 irq_desc */
return radix_tree_lookup(&irq_desc_tree, irq);
struct irqaction *action;
action = __free_irq(irq, dev_id);/* 通过 virq 和 具体的设备dev_id 获取对应的action */
kfree(action);/* 卸载 */
接下来主要分析一下 __free_irq ;
static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
struct irq_desc *desc = irq_to_desc(irq);/* radix tree 方式获取 irq_desc */
return radix_tree_lookup(&irq_desc_tree, irq);
struct irqaction *action, **action_ptr;
action_ptr = &desc->action;/* 从 irq_desc 中获取一个 action 链表 */
for (;;) {
action = *action_ptr;
if (!action) {
WARN(1, "Trying to free already-free IRQ %d\n", irq);
raw_spin_unlock_irqrestore(&desc->lock, flags);
chip_bus_sync_unlock(desc);
mutex_unlock(&desc->request_mutex);
return NULL;
}
if (action->dev_id == dev_id)
break;
action_ptr = &action->next;
}
/* 在 action 中 通过传递进来的参数 dev_id 循环查找对应 dev_id 所对应的 action */
/* Found it - now remove it from the list of entries: */
*action_ptr = action->next;/* 使用二级指针的一个技术删除 链表中的 action */
irq_pm_remove_action(desc, action);
/* If this was the last handler, shut down the IRQ line: */
if (!desc->action) {
irq_settings_clr_disable_unlazy(desc);
irq_shutdown(desc); /* 通过类似状态机的方式切换状态,并关闭中断*/
if (irqd_is_started(&desc->irq_data)) {/* 通过状态的判断是否开启中断*/
__irq_disable(desc, true);
irq_state_set_disabled(desc);/* 切换中断状态,禁止中断*/
irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
mask_irq(desc);
irqd_irq_masked(&desc->irq_data)
return __irqd_to_state(d) & IRQD_IRQ_MASKED;/* 关闭中断 */
irq_state_clr_started(desc);
irqd_clear(&desc->irq_data, IRQD_IRQ_STARTED);/* 关闭中断 */
__irqd_to_state(d) &= ~mask;
irq_domain_deactivate_irq(&desc->irq_data);/* 可以参考gic-v3的datasheet ,这是activate --> deactivate 的切换流程 */
__irq_domain_deactivate_irq(irq_data);
domain->ops->deactivate(domain, irq_data);
irqd_clr_activated(irq_data);
__irqd_to_state(d) &= ~IRQD_ACTIVATED;
}
/* Last action releases resources */
if (!desc->action) {
/*
* Reaquire bus lock as irq_release_resources() might
* require it to deallocate resources over the slow bus.
*/
chip_bus_lock(desc);
irq_release_resources(desc); /* 释放之前设置的一些相关资源0r数据的流程 */
c->irq_release_resources(d);
chip_bus_sync_unlock(desc);
irq_remove_timings(desc);
}
irq_chip_pm_put(&desc->irq_data);/* 通过 runtime PM 的方式对 intc 模块电源的管理,然后再 gic-v3 中并没有使用 */
return action;
}
enable_irq_wake/ disable_irq_wake
enable_irq_wake(fp_dev->irq);
return irq_set_irq_wake(irq, 1);
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
ret = set_irq_wake_real(irq, on);
irq_desc_get_chip(desc)->flags & IRQCHIP_SKIP_SET_WAKE
irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);/* 即从休眠中唤醒中断 */
__irqd_to_state(d) |= mask;
static inline int disable_irq_wake(unsigned int irq)
return irq_set_irq_wake(irq, 0);
struct irq_desc *desc = irq_get_desc_buslock(irq,&flags,IRQ_GET_DESC_CHECK_GLOBAL);
ret = set_irq_wake_real(irq, on);
irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);/* 即进入休眠状态 */
__irqd_to_state(d) &= ~mask;
disable_irq_nosync/enable_irq
silfp_irq_disable(fp_dev);
disable_irq_nosync(fp_dev->irq);
__disable_irq_nosync(irq);
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
__disable_irq(desc);
desc->depth++
irq_disable(desc);
__irq_disable(desc, irq_settings_disable_unlazy(desc));
mask_irq(desc);/* 屏蔽中断 */
desc->irq_data.chip->irq_mask(&desc->irq_data);/* 调用 irq-gic-v3.c 里面的 irq_mask 函数,通过设置inc GICD_ICENABLER 寄存器屏蔽中断*/
gic_mask_irq
gic_poke_irq(d, GICD_ICENABLER);
silfp_irq_enable(fp_dev);
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
__enable_irq(desc);
switch (desc->depth) {/* 这里为 1*/
irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
irq_enable(desc);
unmask_irq(desc);
desc->irq_data.chip->irq_unmask(&desc->irq_data);/* 调用 irq-gic-v3.c 里面的 irq_unmask函数,通过设置inc GICD_ISENABLER 寄存器使能中断*/
gic_unmask_irq
gic_poke_irq(d, GICD_ISENABLER);
综上,再结合我们 fp 的源码,可知 irq 的流程如下所示: