linux中断处理(1)上半部机制
应用程序通过/dev/目录中的设备结点操作设备,通过/sys目录中的收集设备信息.
查看中断:
cat /proc/interrupts
查看中断统计:
cat /proc/stat
1、头文件
#include <linux/interrupt.h>
#include <asm/arch/irqs.h>
2、申明中断处理程序
static spinlock_t wiegand_lock; // 使用之前必须初始化,spin_lock_init(&wiegand_lock);
static irqreturn_t wiegand_minus1_interrupt(int irq, void *dev_id)
{
spin_lock(&wiegand_lock);
//do something
//wiegand_minus_interrupt();
spin_unlock(&wiegand_lock);
return IRQ_HANDLED;
}
3.注册中断 request_irq()
2.6 内核 函数原型如下:
extern int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev_id);
第1个参数:中断号,是要申请的中断号
第2个参数:中断处理函数
第3个参数:中断触发标志
IRQF_DISABLED 快中断(禁止其他中断)
IRQF_TRIGGER_RISING 设备在中断线上产生一个上升沿时,发出中断.(说明在中断之前,设备一直将中断线保持在一个电平上)
IRQF_TRIGGER_FALLING 下降沿触发
IRQF_TRIGGER_HIGH 高电平触发中断
IRQF_TRIGGER_LOW 低电平触发中断
IRQF_TRIGGER_RANDOM 为系统随机发生器提供支持
IRQF_TRIGGER_SHARED (表示共享相同的中断号,多个设备共享)
/*
* linux/interrupt.h
* These correspond to the IORESOURCE_IRQ_* defines in
* linux/ioport.h to select the interrupt line behaviour. When
* requesting an interrupt without specifying a IRQF_TRIGGER, the
* setting should be assumed to be "as already configured", which
* may be as per machine or firmware initialisation.
*/
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
#define IRQF_TRIGGER_PROBE 0x00000010
typedef irqreturn_t (*irq_handler_t)(int, void *);
第4个参数:中断的标识,中断的标识与/proc/interrupts对应
第5个参数:传入中断处理程序的参数,可以为NULL,在注册共享中断时,此参数不能为NULL,作为共享中断时的中断区别参数。
返回值:如果中断处理成功,返回IREQ_HANDLED,否则,返回IRQ_NONE
/* irqreturn.h */
typedef int irqreturn_t;
#define IRQ_NONE (0)
#define IRQ_HANDLED (1)
#define IRQ_RETVAL(x) ((x) != 0)
中断上下文
中断上下文注意事项:
1)中断上下文代码绝不可以停止运行。不能做任何可能发生休眠的操作,在从中断处理函数中调用一个内核API之前,应该仔细分手它,以确保其内部不会触发阻塞等待!
2)为了在中断处理函数中保护临界区,不能使用互斥体,因为它们也许导致睡眠,应该使用自旋锁代替互斥体.
3)中断处理函数不能与用户空间直接交互数据.
调度器工作于进程之间,如果中断处理函数睡眠并被调度出去.无法调度回来!
4)中断处理函数一方面需要快速地为其他进程让出处理器,另一方面又需要完成它的工作,为了规避这种冲突,中断处理函数通常将工作分成两个部分.顶半部设一个标志以宣称它已经服务了该中断,而重大的工作负载都被丢给了底半部,底半部的执行被延后.在其执行环境中,所有的中断都是使能的.
4.释放中断
extern void free_irq(int irq,void *dev_id)
5、启动用禁用中断
extern void disable_irq_nosync(unsigned int irq);
extern void disable_irq(unsigned int irq);
extern void enable_irq(unsigned int irq);