分类: LINUX
2013-09-07 16:07:47
/****************************************************中断处理*********************************************************************/
#include
int request_irq(unsigned int irq,irqreturn_t (*handler)(int, void *),unsigned long flags,const char *dev_name,void *dev_id); //申请中断,成功返回0,负值表示错误码
//函数返回-EBUSY表示该信号线已经被占用
//irq为要申请的中断号,在平台相关目录下的irqs.h中定义
//handler为中断处理函数,其原型为:irqreturn_t xxx_irq(int irq,void *dev_id)
//flags为中断触发方式或中断管理相关的位掩码,在interrupt.h中定义,
//dev_name为中断名,可以根据需要随便写
//dev_id用于共享中断信号线,驱动程序一般使用它指向驱动程序的私有数据区(用来识别那个设备产生中断)
//中断的申请最好在打开设备时
int free_irq(unsigned int irq,void *dev_id);
//中断处理程序:
irqreturn_t xxx_irq(int irq,void *dev_id) //irqreturn_t =int
{
struct xxx_dev *dev=dev_id;
........
wake_up_interruptible(xxx);
return IRQ_RETVAL(IRQ_HANDLED);//中断处理程序应该返回一个值,用来表明是否真正处理了一个中断,如果中断例程发现其设备的确要处理,则应该返回IRQ_HANDLED,
//否则应该返回IRQ_NONE,我们可以通过这个宏来产生返回值,不是本设备的中断应该返回IRQ_NONE
}
/*
*中断处理程序中不能向用户空间发送或者接收数据,也不能做任何可能发送休眠的操作并且不能调用schdule函数
*中断处理程序一个典型的任务就是:如果中断通知进程所等待的事情已经发生,比如新的数据到达,就会唤醒在该设备上休眠的进程
*无论是快速还是慢速处理例程,中断服务程序执行时间应尽可能的短,如果需要执行一个长时间的计算任务,最好的方法是使用tasklet或者工作队列在更安全的时间内调度计算任务
*可通过命令查看系统使用的中断号:cat /proc/interrupts
*/
//禁止单个中断:
#include
void disable_irq(int irq); //禁止某个特定的中断线,而且还会等待当前正在执行的中断处理例程完成
void disable_irq_nosync(int irq);//功能同disable_irq,但会立即返回
void enable_irq(int irq); //使能中断
//禁止所有中断:
#include
void local_irq_save(unsigned long flags);//把当前中断状态保存到flags中,然后禁止当前处理器上的中断
void local_irq_disable(void);//直接禁止中断,只有在我们知道中断并未在其他地方被禁止的情况下才能使用它
//打开所有的中断:
void local_irq_restore(unsigned long flags);
void local_irq_enable(void);
/*
linux通过中断处理例程分成两部分来解决中断要完成一定数据的工作问题,“顶半部”的部分用于完成必要的工作,用于快速响应,也就是 request_irq注册的中断例程,而所谓的“底半部”是一个
被顶半部调度,并在稍后更安全的时间内执行的例程,与顶半部最大的不同是底半部处理例程执行时,所有的中断都是打开的,典型的情况是顶半部保存设备的数据到一个特定的缓冲区并调度它的底半部,然后退出。
linux提供了两种机制用来实现底半部处理,tasklet通常是底半部的优选机制,因为这种机制非常快,但所有的tasklet代码必须是原子的。还可以选择工作队列,它可以具有更高的延迟,但允许休眠。
tasklet可确保和第一次调度它们的函数运行在同样的cpu上,这样,因为tasklet在中断处理例程结束前不会开始运行,所以此时的中断处理例程是安全的,在tasklet运行时,可以有其他中断,因此在tasklet
和中断例程之间的锁还是需要的
*/
//共享中断:
1:flags被设置为IRQF_SHARED
2:dev_id参数必须是唯一的,任何指向模块的地址空间的指针都可以用,但它不能被设置为NULL。
/****************************************************end**********************************************************************/