分享

linux中断之中断注册

 若渴若愚 2012-07-03

linux中断之中断注册

 

专业的linux驱动开发离不开中断处理,在处理中断,首先要注册中断,在linux下通过request_irq来注册中断的,不同内核版本,注册中断所需要的参数也不同,本文以linux-2.6.34为例,对比老版本进行说明。

request_irq()函数在include/linux/interrupt.h中定义,原型为:

static inline int __must_check

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)

参数说明:

unsigned int irq:注册中断服务程序对应的硬件中断号;

irq_handler_t handler:注册的中断服务程序,函数指针,原型定义为:typedef irqreturn_t (*irq_handler_t)(int, void *);

unsigned long flags:中断标志,表明中断程序的属性,注意,在新老内核中,相关属性定义不同。具体参考后面的中断标志位说明;

const char *name:与该中断相关联的名称,在/proc/interrupt中可看到。

void *dev:中断服务程序的参数,可以为NULL,但在注册共享中断时,此参数不能为NULL。

中断标志位

新版本中的IRQF_XXX替代了老版本中的SA_XXX,主要标志包括以下:

IRQF_DISABLED:快速中断标志,对应老版本中的SA_INTERRUPT标志,表明在处理本中断时屏蔽所有中断,而在没设置此标志位的程序中,都是开中断处理的,可以进行中断嵌套。

IRQF_SAMPLE_RANDOM:用于随机数据产生;

IRQF_SHARED:用于共享中断,设置此标志时,request_irq最后一个参数dev不能为NULL,对应老版本内核的SA_SHIRQ;

IRQF_PROBE_SHARED:探测共享中断;

IRQF_TIMER:专用于定时中断;

IRQF_PERCPU:Interrupt is per cpu

IRQF_NOBALANCING:Flag to exclude this interrupt from irq balancing

IRQF_IRQPOLL:Interrupt is used for polling(only the interrupt that is registered first in an shared interrupt is considered for performance reasons)

IRQF_ONESHOT:Interrupt is not reenabled after the hardirq handler finished. Used by threaded interrupts which need to keep the irq line disabled until the threaded handler has been run.

注册中断

相关实现在kernel/irq/manage.c中。

static inline int __must_check
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);
}

int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags,
const char *devname, void *dev_id)
{
struct irqaction *action;
struct irq_desc *desc;
int retval;

/*
* handle_IRQ_event() always ignores IRQF_DISABLED except for
* the _first_ irqaction (sigh). That can cause oopsing, but
* the behavior is classified as "will not fix" so we need to
* start nudging drivers away from using that idiom.
*/
if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) == //共享中断不能作为快速中断。
(IRQF_SHARED|IRQF_DISABLED)) {
pr_warning(
"IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
irq, devname);
}

#ifdef CONFIG_LOCKDEP //若定义此宏,则禁止中断嵌套,所有中断都关中断运行。
/*
* Lockdep wants atomic interrupt handlers:
*/
irqflags |= IRQF_DISABLED;
#endif
/*
* Sanity-check: shared interrupts must pass in a real dev-ID,
* otherwise we'll have trouble later trying to figure out
* which interrupt is which (messes up the interrupt freeing
* logic etc).
*/
if ((irqflags & IRQF_SHARED) && !dev_id) //共享中断必须设置dev_id参数
return -EINVAL;

desc = irq_to_desc(irq); //找到该中断号对应的irq_desc,即全局数组irq_desc的第irq个表项。
if (!desc) //所有irq_desc在系统启动时,通过init_IRQ初始化。
return -EINVAL;

if (desc->status & IRQ_NOREQUEST) //若此中断禁止响应,则返回。
return -EINVAL;

if (!handler) { //中断服务程序不能为NULL
if (!thread_fn)
return -EINVAL;
handler = irq_default_primary_handler;
}

action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action) //中断的入口是irq_desc->handle_irq或__do_IRQ(),但我们注册的中断处理程序都是irq_desc下的一个action。
return -ENOMEM;

action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;

chip_bus_lock(irq, desc);
retval = __setup_irq(irq, desc, action); //注册中断处理,将action挂到irq_desc->action中,或初始化中断线程等...
chip_bus_sync_unlock(irq, desc);

if (retval)
kfree(action);

#ifdef CONFIG_DEBUG_SHIRQ //用于调试共享中断。
if (!retval && (irqflags & IRQF_SHARED)) {
/*
* It's a shared IRQ -- the driver ought to be prepared for it
* to happen immediately, so let's make sure....
* We disable the irq to make sure that a 'real' IRQ doesn't
* run in parallel with our fake.
*/
unsigned long flags;

disable_irq(irq);
local_irq_save(flags);

handler(irq, dev_id);

local_irq_restore(flags);
enable_irq(irq);
}
#endif
return retval;
}


中断处理程序的返回值是一个特殊类型:irqreturn_t。中断处理程序可能会返回两个特殊的值:IRQ_NONEIRQ_HANDLED。当中断处理程序检测到一个中断,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是它所对应的设备产生了中断,返回IRQ_HANDLED。而实际上irqreturn_t就是一个int类型。

中断处理程序通常会标记为static,因为它从来不会被别人的文件中的代码直接调用。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多