Linux 驱动中断处理

来源:互联网 发布:java垃圾回收优点 编辑:程序博客网 时间:2024/06/05 19:25
中断分为:内部中断、外部中断, 可屏蔽中断、不可屏蔽中断(NMI)、向量中断、非向量中断
向量中断由硬件提供中断服务程序入口地址
非向量中断由软件提供中断服务程序入口地址。


linux 中断编程
10.3.1 申请和释放中断
request_irq() free_irq()
1.申请IRQ
int request_irq(unsigned int irq,
void(*handler)(int irq, void *dev_id, struct pt_regs *regs),
unsigned long irqflags,
const char *devname,
void *dev_id);
irq是要申请的硬件中断号。
handler是向系统登记的中断处理函数
irqflags是中断处理的属性,若设置了SA_INTERRUPT,则表示中断处理程序是快速处理程序,
快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽。
若设置了SA_SHIRQ,则表示多个设备共享中断
dev_id 在中断共諿时会用到,一般设置为这个设备结构体,或者NULL。
request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回
-EBUSY表示中断已经被占用且不能共享。


irqflags 有以下:


#define IRQF_TRIGGER_RISING 0x00000001   //上升沿触发
#define IRQF_TRIGGER_FALLING 0x00000002 //下降沿触发
#define IRQF_TRIGGER_HIGH 0x00000004//高电平触发
#define IRQF_TRIGGER_LOW 0x00000008     //低电平触发


#define IRQF_DISABLED 0x00000020   
#define IRQF_SAMPLE_RANDOM 0x00000040
#define IRQF_SHARED 0x00000080
#define IRQF_PROBE_SHARED 0x00000100
#define __IRQF_TIMER 0x00000200
#define IRQF_PERCPU 0x00000400
#define IRQF_NOBALANCING 0x00000800
#define IRQF_IRQPOLL 0x00001000
#define IRQF_ONESHOT 0x00002000
#define IRQF_NO_SUSPEND 0x00004000
#define IRQF_FORCE_RESUME 0x00008000
#define IRQF_NO_THREAD 0x00010000




2.释放IRQ
与request_irq()向对应的函数为free_irq()
void free_irq(unsigned int irq, void *dev_id);


10.3.2使能和屏蔽中断
void disable_irq(int irq);
void disable_irq_nosync(int irq);
void enable_irq(int irq);


disable_irq_nosync()与disable_irq()的区别在于前者立即返回,而后者等待目前的中断处理完成。
以上中断操作对系统内的所有CPU都生效。


下列两个函数将屏蔽本CPU内的所有中断
void local_irq_save(unsigned long flags);
void local_irq_disable(void);


void local_irq_restore(unsigned long flags);
void local_irq_enable(void);


10.3.3底半部机制
Linux系统实现底半部的机制主要有tasklet 工作队列和软中断。
1.tasklet
void my_tasklet_func(unsigned long); //定义一个处理函数
DECLARE_TASKLET(my_tasklet, my_tasklet_func, data);//定义一个tasklet结构my_tasklet 与my_tasklet_func函数关联
在需要调度tasklet的时候引用一个tasklet_schedule()函数就能使系统在适当的时候进行调度运行
tasklet_schedule(&my_tasklet);


10.2 tasklet使用模板
/*定义tasklet和底半部函数并关联*/
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);


/*中断处理底半部*/
void xxx_do_tasklet(unsigned long)
{
....
}


/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
...
tasklet_schedule(&xxx_tasklet);
...
return IRQ_HANDLED;
}


/*设备驱动模块加载函数*/
int __init xxx_init(void)
{
...
/*申请中断*/
result = request_irq(xxx_irq, xxx_interrupt,
SA_INTERRUPT,"XXX",NULL);

...
}




/*设备驱动模块卸载函数*/
void __exit xxx_exit(void)
{
....
free_irq(xxx_irq, xxx_interrupt);
....

}