ARM Linux对中断的处理--中断注册方法

中断注册方法
在驱动程序中,要想使设备能够产生中断,则首先需要调用request_irq()来分配中断线。在通过request_irq()函数注册中断服务程序的时候,将会把设备中断处理程序添加进系统,以在中断发生的时候调用相应的中断处理程序。我们来看一下request_irq()函数的定义:
---------------------------------------------------------------------
include/linux/interrupt.h
121 static inline int __must_check
122 request_irq(unsigned int irq, irq_handler_t handler, unsigned long
123             flags, const char *name, void *dev)
124 {
125         return request_threaded_irq(irq, handler, NULL, flags, name, dev);
126 }
---------------------------------------------------------------------
在2.6.34版的内核里面,request_irq()函数是request_threaded_irq()函数的封装,request_threaded_irq()函数定义如下:
---------------------------------------------------------------------
kernel/irq/manage.c
1038 int request_threaded_irq(unsigned int irq, irq_handler_t handler,
1039               irq_handler_t thread_fn, unsigned long irqflags,
1040               const char *devname, void *dev_id)
1041 {
1042   struct irqaction *action;
1043   struct irq_desc *desc;
1044   int retval;
1045
1046   /*
1047    * handle_IRQ_event() always ignores IRQF_DISABLED except for
1048    * the _first_ irqaction (sigh).  That can cause oopsing, but
1049    * the behavior is classified as "will not fix" so we need to
1050    * start nudging drivers away from using that idiom.
1051    */
1052   if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==
1053                   (IRQF_SHARED|IRQF_DISABLED)) {
1054      pr_warning(
1055      "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
1056           irq, devname);
1057   }
1058
1059 #ifdef CONFIG_LOCKDEP
1060   /*
1061    * Lockdep wants atomic interrupt handlers:
1062    */
1063   irqflags |= IRQF_DISABLED;
1064 #endif
1065   /*
1066    * Sanity-check: shared interrupts must pass in a real dev-ID,
1067    * otherwise we'll have trouble later trying to figure out
1068    * which interrupt is which (messes up the interrupt freeing
1069    * logic etc).
1070    */
1071   if ((irqflags & IRQF_SHARED) && !dev_id)
1072           return -EINVAL;
1073
1074   desc = irq_to_desc(irq);
1075   if (!desc)
1076           return -EINVAL;
1077
1078   if (desc->status & IRQ_NOREQUEST)
1079           return -EINVAL;
1080
1081   if (!handler) {
1082           if (!thread_fn)
1083                   return -EINVAL;
1084           handler = irq_default_primary_handler;
1085   }
1086
1087   action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
1088   if (!action)
1089           return -ENOMEM;
1090
1091   action->handler = handler;
1092   action->thread_fn = thread_fn;
1093   action->flags = irqflags;
1094   action->name = devname;
1095   action->dev_id = dev_id;
1096
1097   chip_bus_lock(irq, desc);
1098   retval = __setup_irq(irq, desc, action);
1099   chip_bus_sync_unlock(irq, desc);
1100
1101   if (retval)
1102           kfree(action);
1103
1104 #ifdef CONFIG_DEBUG_SHIRQ
1105   if (!retval && (irqflags & IRQF_SHARED)) {
1106     /*
1107      * It's a shared IRQ -- the driver ought to be prepared for it
1108      * to happen immediately, so let's make sure....
1109      * We disable the irq to make sure that a 'real' IRQ doesn't
1110      * run in parallel with our fake.
1111      */
1112     unsigned long flags;
1113
1114     disable_irq(irq);
1115     local_irq_save(flags);
1116
1117     handler(irq, dev_id);
1118
1119     local_irq_restore(flags);
1120     enable_irq(irq);
1121   }
1122 #endif
1123   return retval;
1124 }
1125 EXPORT_SYMBOL(request_threaded_irq);
---------------------------------------------------------------------
内核用这个函数来完成分配中断线的工作,其各个参数说明如下:
irq,是要注册的硬件中断号;
handler,是向系统注册的中断处理函数,它是一个回调函数,在相应的中断线发生中断时,系统会调用这个函数;
irqflags,中断类型标志,IRQF_*,是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版中已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED(老版本中的SA_SHIRQ),则表示是多个设备共享同一个中断;若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示将对系统熵有贡献,对系统获取随机数有好处,还可以用IRQF_TRIGGER_*标志来指定中断的触发方式。(这几个flag是可以通过或的方式同时使用的)。;
devname,一个声明的设备的ascii 名字,与中断号相关联的名称,在/proc/interrupts文件中可以看到此名称。
dev_id,I/O设备的私有数据字段,典型情况下,它标识I/O设备本身(例如,它可能等于其主设备号和此设备号),或者它指向设备驱动程序的数据,这个参数会被传回给handler函数。在中断共享时会用到,一般设置为这个设备的驱动程序中任何有效的地址值或者NULL
thread_fn,由irq handler线程调用的函数,如果为NULL,则不会创建线程。
 
这个调用分配中断资源,并使能中断线和IRQ处理。这个调用完成之后,则注册的中断处理函数随时可能被调用。由于你的中断处理函数必须清除板子产生的一切中断,则你必须注意初始化你的硬件和设置中断处理函数的正确顺序。
 
如果你想为你的设备设置线程化的irq处理程序,则你需要同时提供handler 和thread_fn。handler仍然在硬中断上下文被调用,所以它需要检查中断是否是由它服务的设备产生的。如果是,它返回IRQ_WAKE_THREAD,这将会唤醒中断处理程序线程并执行thread_fn。这种分开的中断处理程序设计是支持共享中断所必需的。Dev_id必须全局唯一。通常是设备数据结构的地址。如果要使用的共享中断,则必须传递一个非NULL的dev_id,这是在释放中断的时候需要的。
 
request_threaded_irq()函数返回0表示成功,返回-EINVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断号已经被占用且不能共享。这个函数完成的操作如下:
1、检查传递进来的标志参数irqflags,是否同时设置了IRQF_SHARED和IRQF_DISABLED,若是则发出警告,以说明IRQF_DISABLED在共享的中断上是不被保证的。
2、若irqflags设置了IRQF_SHARED,则还要检查dev_id的有效性。
3、获得对应中断号的中断描述符,并检查其有效性(通过检查中断描述符status字段的IRQ_NOREQUEST位)。
4、检查handler及thread_fn的有效性。
5、为注册的中断处理程序及传递的irqaction标志创建irqaction结构。
6、调用__setup_irq(irq, desc, action),来将创建的irqaction结构添加进相应的中断描述符的action链表里。
 

关于中断注册的例子,可在内核中搜索下request_irq。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值