linux-3.14版本;
1. request_irq
原型: int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
作用:向内核注册一个中断处理函数;
参数1:IRQ号,用于决定构造的struct irqaction结构体对象被插入到哪个链表;
参数2:typedef irqreturn_t (*irq_handler_t)(int, void *); 指向中断处理函数的函数指针;
参数3:IRQF_开头的中断相关标志; 常见的几种;如下:
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001 //上升沿触发
#define IRQF_TRIGGER_FALLING 0x00000002 //下降沿触发
#define IRQF_TRIGGER_HIGH 0x00000004 //高电平触发
#define IRQF_TRIGGER_LOW 0x00000008 //低电平触发
#define IRQF_SHARED 0x00000080 //共享中断必须设置的标志
#define __IRQF_TIMER 0x00000200 //定时器专用中断标志
参数4:该中断在/proc中的名字;
参数5:区别共享中断中不同设备所对应的struct irqaction结构体对象;共享中断必须传一个非NULL实参,非共享中断可以为NULL;
返回值:成功返回0; 失败返回负数;
2. free_irq
void free_irq(unsigned int irq, void *dev_id)
作用: 注销一个中断处理函数;
参数1:IRQ号;
参数2:共享中断必须传一个有requist_irq参数5相同的非NULL实参;
3. 内核源码阅读笔记
request_irq调用request_threaded_irq,然后又调用__setup_irq函数;
//以下代码块必须以原子方式执行
raw_spin_lock_irqsave(&desc->lock, flags);
//遍历irq所在irqaction链表,遍历到末尾结束;
old_ptr = &desc->action;
old = *old_ptr;
if (old) {
/* add new interrupt at end of irq queue */
do {
/*
* Or all existing action->thread_mask bits,
* so we can find the next zero bit for this
* new action.
*/
thread_mask |= old->thread_mask;
old_ptr = &old->next;
old = *old_ptr;
} while (old);
shared = 1;
}
...
//将新的通过irq构造的struct irqaction对象加入链表尾
new->irq = irq;
*old_ptr = new;//加入链表尾部
if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
desc->istate &= ~IRQS_SPURIOUS_DISABLED;
__enable_irq(desc, irq, false);//使能中断
}
raw_spin_unlock_irqrestore(&desc->lock, flags);
//在proc下生成信息
register_irq_proc(irq, desc);
new->dir = NULL;
register_handler_proc(irq, new);
free_cpumask_var(mask);
return 0;//成功返回0
free_irq函数调用kfree(__free_irq(irq, dev_id)); 其中__free_irq函数返回找到的struct irqaction;
static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{
raw_spin_lock_irqsave(&desc->lock, flags);
action_ptr = &desc->action;
//遍历irq所在的action链表,通过dev_id找到对应的struct irqaction对象
for (;;) {
action = *action_ptr;
if (!action) {
WARN(1, "Trying to free already-free IRQ %d\n", irq);
raw_spin_unlock_irqrestore(&desc->lock, flags);
return NULL;
}
if (action->dev_id == dev_id)
break;
action_ptr = &action->next;
}
...
raw_spin_unlock_irqrestore(&desc->lock, flags);
unregister_handler_proc(irq, action); //注销/proc下相关信息
...
return action; //找到返回该对象,然后kfree掉;
}