-
关于中断的理解
中断你可以理解为就是一种电信号,是由硬件设备产生的然后发送给处理器,处理器接收到中断后,就会马上向操作系统反映此信号,之后就是系统的工作了。
这里有两个注意的地方,第一中断是随时都可以产生,意味着中断的处理程序随时都可以执行,所以得保证中断处理程序能够快速执行,才可能尽快的恢复中断代码执行,所以中断代码尽量简短。第二每一个中断都有自己唯一的数字标记,这样操作系统才能对症下药
-
中断上半部,下半部理解
顶半部完成尽可能少的比较紧急的功能,它往往只是简单地读取寄存器中的中断状态并清除中断标志后就进行“登记中断”的工作。“登记中断”意味着将底半部处理程序挂到该设备的底半部执行队列中去。这样,顶半部执行的速度就会很快,可以服务更多的中断请求。现在,中断处理工作的重心就落在了底半部的头上,它来完成中断事件的绝大多数任务。底半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断,这也是底半部和顶半部的最大不同,因为顶半部往往被设计成不可中断。底半部则相对来说并不是非常紧急的,而且相对比较耗时,不在硬件中断服务程序中执行。
上半部注册函数:request_irq()
下半部分一般有tasklet、工作队列实现,触摸屏中中断实现以工作队列形式实现的。
-
中断如何划分出上下两部分
如果一个任务对时间十分敏感,将其放在上半部。
如果一个任务和硬件有关,将其放在上半部。
如果一个任务要保证不被其他中断打断,将其放在上半部。
其他所有任务,考虑放在下半部。
-
上半部的处理
中断处理程序是管理硬件的驱动程序的组成部分,每一设备都有相关的驱动程序,驱动程序可以通过request_irq()函数注册一个中断处理程序,并且激活给定的中断线,来处理指定的中断,原型如下:
int request_irq(unsigned int irq, irq_handler_t handler, \
unsigned long flags, const char *devname, void *dev_id)
第一个参数irq表示要分配的中断号,就我目前所接触的都是预先已经预定好的,还没试着通过探测或者动态来确定中断号
第二个参数handler是一个指针,指向处理这个中断的实际中断处理程序,只要操作系统一接收到中断,该函数就被调用,这个函数稍后讨论
第三个参数flags中断处理程序的标志,这个标志可以是一个也可以是多个,列举几个最重要的标志:
IRQF_DISABLED: 该标志被设置后,意味内核在处理中断处理程序本身的时候,禁止了其他所有的中断。如果不设置,中断处理程序可 以与除本身之外的其他任何中断同时运行。显而易见我们一般不去这么野蛮的设置这个标志
IRQF_TIMER:为系统定时器的中断处理而准备的
IRQF_SHARED:这个中断标志经常能遇见,这个标志意思就是多个中断处理程序之间可以共享中断线,概括起来就是没有这个标志就只能独自一个人占用,标志了,就是很多人可以占用这个中断号来
第四个才参数就是自定义与中断设备相关的文本了
第五个参数dev,看到第三个参数中IRQF_SHARED时候,你会不会有这样的疑问,假如现在我要释放当前共享的指定这个中断程序时候,我如何释放?会不会把其他占用也会删除掉,这就是第五个参数的意义,如果中断线是共享的,那么就必须传递能够代表当前设备的唯一信息
request_irq()成功返回0,如果返回非0,就表示有错误发生,这个时候你可以考虑当前中断是否被占用了,所以可以加上IRQF_SHARED标志
-
下半部的处理
实现下半部中断的三种机制:
1.软中断
2.tasklet
3.工作队列
-
工作队列demo
使用方法和tasklet类似
相关操作:
struct work_struct my_wq; //定义一个工作队列
void my_wq_func(unsigned long); //定义一个处理函数
通过INIT_WORK()可以初始化这个工作队列并将工作队列与处理函数绑定
INIT_WORK(&my_wq,(void ()(void ))my_wq_func,NULL);
/*初始化工作队列并将其与处理函数绑定*/
schedule_work(&my_wq);/调度工作队列执行/
/*定义工作队列和关联函数*/
struct work_struct xxx_wq(unsigned long);
/*中断处理底半部*/
void xxx_do_work(unsigned long){...}
/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id)
{
//TODO
schedule_work(&my_wq);
}
/*设备驱动模块加载函数*/
int xxx_init(void)
{
//TODO
//申请中断
//原型:int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
request = request_irq(xxx_wq,xxx_interrupt,IRQF_DISABLED,"XXX",NULL);
...
// 初始化工作队列
INIT_WORK(&my_wq,(void(*)(void *))xxx_do_work,NULL )
}
/*设备驱动模块卸载函数*/
void xxx_exit(void)
{
//TODO
//释放中断
free_irq(xxx_irq,xxx_interrupt);
//TODO
}