中断的概念我想大家都很清楚,在我们学习单片机的时候接触很多,所以这里就不再赘述了。
在linux设备驱动程序中,中断处理相关的首先是申请与释放IRQ的API是:
request_irq()和free_irq()
request_irq()的原型是
int request_irq(unsigened int irq,void (*handler)(int irq,void *dev_id , struct pt_regs *regs , unsigned long irqflags, count char * devname , void * dev_id))
irq:是要申请的硬件中断号,
handler:是向系统登记的中断处理函数,是一个回调函数,中断发生使,系统调用这个函数
dev_id 参数将被传递
irqflags :是中断处理的属性,若设置SA_INTERRUPT标明中断处理程序是快速处理程序。
快速处理程序被调用时屏蔽所有中断,慢处理程序不屏蔽。
若设置SA_SHIRQ 则多个设备共享中断,dev_id在中断共享时会用到,一般设置为该设备的device结构本身或者NULL
free_irq()的原型是
void free_irq( unsigend itn irq , void * dev_id )
另外非常重要的是:
linux中断分为两个半部。
上半部分的功能是“登记中断”,当一个中断发生时,它进行相应的硬件读写后,把中断例程的下半部分挂到该设备的下半部分执行队列中去。
下半部分的作用 几乎做了中断处理程序的所有的事情,而且可以被新的中断打断。而上半部分是不可中断的。
这样在我们响应中断时需要非常快速,而在处理时则不必太紧急,而可以处理响应新产生的中断。
linux实现下半部的机制主要是tasklet和工作队列
tasklet 基于 Linux softirq
通过定义tasklet及其处理函数并将二者关联:
void my_tasklet_func(unsigned long);//定义一个处理函数
DECLARE_TASKLET(my_tasklet , my_tasklet_func ,data)//定义一个tasklet结构my_tasklet 与my_tasklet_func(data)相关联。
接着我们来运行一个实例
在我们上篇博客中的驱动程序文件中添加如下代码:
http://blog.csdn.net/zhaole20094463/article/details/7907007
void test_tasklet_action(unsigned long t);
DECLARE_TASKLET(test_tasklet, test_tasklet_action ,0);
void test_tasklet_action(unsigned long t)
{
printk(KERN_EMERG"tasklet is executing\n");
}
修改该文件write函数
static ssize_t chardev_write(struct file *filp,const char *buf,size_t len,loff_t *off)
{
if(down_interruptible(&sem))
{
return -ERESTARTSYS;
}
if(copy_from_user(&chardev_var,buf,sizeof(int)))
{
up(&sem);
return -EFAULT;
}
tasklet_schedule(&test_tasklet);//在此处产生中断。
up(&sem);
flag = 1;
wake_up_interruptible(&outq);
return sizeof(int);
}
该模块完成的功能就是在该设备被写入一个字符后即可出发中断,中断打印出我们中断服务子函数中的语句。
编译完成后加载模块,创建设备节点,使用
http://blog.csdn.net/zhaole20094463/article/details/7907007该博客中的写测试程序即可
在我们输入一个字符后产生中断,
打印 tasklet is executing
备注:如果没有打印信息的话多试几次,我的就是由于系统的原因,第一次存储在了缓冲区里,再测试一次的时候打印信息就正常了。