Kernel之共享中断
Kernel之共享中断
背景
最近有个测试用例的需求,是关于中断管理的。
在现有的硬件基础上,实现以下功能:
- 缺省情况下提供默认的中断处理程序
- 能使能和屏蔽某一特定中断
后面用共享中断实现了这个测试用例
共享中断
有时候多个设备可能共享一根硬件中断线,在现实应用场景中广泛存在,特别像PCI控制器,GPIO等,所以内核提供了这种中断共享的机制。
下面是中断共享的使用及注意点:
- 共享中断的多个设备在申请中断时,都应加上
IRQF_SHARED
标志,而且一个设备以IRQF_SHARED
申请某中断成功的前提是该中断未被申请,或该中断虽然被申请了,但是之前申请该中断的所有设备也都以IRQF_SHARED标志申请该中断。- 尽管内核模块可访问的全局地址都可以作为request_irq(…,void*dev_id)的最后一个参数dev_id,但是设备结构体指针显然是可传入的最佳参数。
- 在中断到来时,会遍历执行共享此中断的所有中断处理程序,直到某一个函数返回IRQ_HANDLED。在中断处理程序顶半部中,应根据硬件寄存器中的信息比照传入的dev_id参数迅速地判断是否为本设备的中断,若不是,应迅速返回IRQ_NONE,如下图所示。
共享中断伪代码实现:
/* 中断处理函数 */
static irqreturn_t irq_test_handler(int irq, void *data)
{
printk("This is a test to verify the interrupt!\n");
/*
这里可以加入判断是否为本设备中断, 不是本设备中断,立即返回 IRQ_NONE ;
可以通过申请中断时传入的最后一个参数,来获取需要判断的依据,即这里的data,一般为设备的数据结构体
*/
return IRQ_HANDLED;
}
/* 在驱动的probe函数或是init函数中申请中断 */
static int irq_test_probe(struct platform_device *pdev)
{
...
/*
见下面备注
*/
ret = request_threaded_irq(i_data->test_irq_num, NULL, irq_test_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED,
"elan_ts"/*pdev->name*/, i_data);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request irq_test_device IRQ\n");
goto out2;
}
...
}
/* 在驱动的remove函数或是exit函数中释放中断 */
static int irq_test_remove(struct platform_device *pdev)
{
...
if(data->test_irq_num > 0)
/* 注意这里最后一个参数要和申请时的最后一个参数对应 */
free_irq(data->test_irq_num, (void *)data);
...
}
备注:
- 要共享中断,在每个申请中断的时候,最重要的就是标志flag里的
IRQF_SHARED
标志位都要设置,触发类型标志位要匹配,还有这里的”elan_ts”要和共享中断的设备名一致,不然会报 mismatch 错误 - 这里我们共享的是elan触摸屏的中断,所以和elan驱动中申请中断时的设备名一致; 同时,elan驱动中申请中断时也需要加上 IRQF_SHARED 标志
- 有些中断是不能共享的,比如NMIs不可屏蔽中断等
内核里的原始说明:
/*
* Can't share interrupts unless both agree to and are
* the same type (level, edge, polarity). So both flag
* fields must have IRQF_SHARED set and the bits which
* set the trigger type must match. Also all must
* agree on ONESHOT.
* Interrupt lines used for NMIs cannot be shared.
*/
具体的可以参见内核里面的代码
参考
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DD'Notes!
评论