首页 理论教育 Linux驱动程序:硬件中断处理实例

Linux驱动程序:硬件中断处理实例

时间:2023-10-19 理论教育 版权反馈
【摘要】:处理器一旦检测到该信号,便中断自己当前正在处理的工作,转而去处理中断。图6-7是中断处理原理图。下半部是可中断的,而上半部是不可中断的,处理完毕立即返回。handler为主处理函数,thread_fn为中断处理线程函数。中断处理函数应该快速退出并让出处理器,不能与用户空间交换数据,不能调用能引起睡眠的函数,并应确保其内部不会触发阻塞等待。另外中断处理函数可以被更高优先级IRQ的中断处理函数打断。

Linux驱动程序:硬件中断处理实例

从物理学的角度看,硬件中断是一种电信号,由硬件设备产生,并直接送入中断控制器输入引脚上,再由中断控制器向处理器发送相应的信号。处理器一旦检测到该信号,便中断自己当前正在处理的工作,转而去处理中断。图6-7是中断处理原理图。

978-7-111-56706-6-Chapter06-41.jpg

图6-7 中断处理原理

如果中断处理过程非常复杂,可以分成两部分:上半部(top half)和下半部(bottom half)。上半部完成一些急需处理的事务,如从硬件读取信息,下半部完成余下的复杂的运算或逻辑处理。下半部是可中断的,而上半部是不可中断的,处理完毕立即返回。Linux中的中断下半部包括软中断、tasklet机制和工作队列等。

Linux内核中的中断请求队列用irq_desc结构描述:

978-7-111-56706-6-Chapter06-42.jpg

978-7-111-56706-6-Chapter06-43.jpg

IRQ服务列表的结构描述为:

978-7-111-56706-6-Chapter06-44.jpg

不同的设备对应的中断都用一个唯一的整型数据标识,这个整型数据叫作中断号。request_irq函数用于申请中断,原型如下:

int request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char*name,void*dev);

参数irq表示所要申请的硬件中断号。name为中断名称。dev为设备参数。handler为中断处理函数,中断产生时系统会调用该函数:

typedef irqreturn_t(*irq_handler_t)(int,void*);

irq_handler_t的第一个参数为中断号。

flags是申请时的选项,它决定中断处理程序的一些特性:

#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_TRIGGER_NONE 0x00000000//未设置触发方式

#define IRQF_TRIGGER_RISING 0x00000001//上升沿

#define IRQF_TRIGGER_FALLING 0x00000002//下降沿(www.xing528.com)

#define IRQF_TRIGGER_HIGH 0x00000004//高电平

#define IRQF_TRIGGER_LOW 0x00000008//低电平

中断处理程序的返回值有三种:

978-7-111-56706-6-Chapter06-45.jpg

申请中断时如果需要为设备建立一个中断后处理线程,可以使用request_threaded_irq函数。

978-7-111-56706-6-Chapter06-46.jpg

handler为主处理函数,thread_fn为中断处理线程函数。如果中断主处理函数handler返回IRQ_WAKE_THREAD,则会唤醒中断线程。假如handler为空,则采用默认的主处理函数irq_default_primary_handler:

978-7-111-56706-6-Chapter06-47.jpg

978-7-111-56706-6-Chapter06-48.jpg

free_irq函数用来释放一个中断:

void free_irq(unsigned int irq,void*dev_id);

ARM体系中处理中断的函数为asm_do_IRQ。asm_do_IRQ函数在entry-macro-multi.S中被调用:

978-7-111-56706-6-Chapter06-49.jpg

asm_do_IRQ定义如下:

978-7-111-56706-6-Chapter06-50.jpg

generic_handle_irq函数调用了generic_handle_irq_desc函数,进而调用了中断处理函数。

978-7-111-56706-6-Chapter06-51.jpg

handle_irq函数最终会调用irqaction结构的handler成员,也就是request_irq函数注册的中断处理函数。在中断上下文中,有一些需要注意的地方。中断处理函数应该快速退出并让出处理器,不能与用户空间交换数据,不能调用能引起睡眠的函数,并应确保其内部不会触发阻塞等待。在中断处理函数中保护临界区,不能使用互斥体,因为它们可能导致睡眠,真正需要保护临界区的时候应该使用自旋锁。中断处理函数不必是可重用的。当某中断被执行的时候,在它返回之前,相应的IRQ都被禁止了。因此,与进程上下文代码不同的是,同一中断处理函数的不同实例不可能同时运行在多个处理器上。另外中断处理函数可以被更高优先级IRQ的中断处理函数打断。

禁止与允许中断的函数包括:

void disable_irq(int irq);//禁止单个中断,等待成功返回

void disable_irq_nosync(int irq);//禁止单个中断,不等待返回

void enable_irq(int irq);//允许单个中断

void local_irq_save(unsigned long flags);//禁止所有中断,并保存标志

void local_irq_diable(void);//禁止所有中断

void local_irq_restore(unsigned long flags);//使能所有中断,并恢复标志

void loval_irq_enable(void);//使能所有中断

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈