慢速设备总是和处理器在不同的时间周期工作,如果让处理器主动去读取设备的状态,这样就会浪费cpu资源。所以可以让设备就绪需要处理器的时候产生某个事件来通知处理器。这就是中断的方式。
一、安装中断处理例程
安装中断处理例程以及申请中断信号线函数如下:
int request_irq(unsigned int irq, irqreturn_t (handler)(int, void, struct pt_regs *), unsigned long flags, const char *dev_name, void *dev_id);
void free_irq(unsigned int irq, void *dev_id);
调用request_irq的正确位置应该是在设备第一次打开、硬件被告知产生中断之前。调用free_irq的位置是最后一次关闭设备、硬件被告知不用再中断处理器之后。
一般目标设备都有能力告诉驱动程序它将使用的中断号。如果不清楚的话可以通过内核探测来确定IRQ号。
二、实现中断处理例程
1.启用和禁用中断
禁用单个中断,如下函数会在所有的处理器上禁用或者启用IRQ。
void disable_irq(int irq);
void disable_irq_nosync(in irq);
void enable_irq(int irq);
禁用所有的中断,但只能关闭当前处理器上的所有中断,函数如下:
void local_irq_save(unsigned long flags);
void local_irq_disable(void);
对应的打开中断的函数如下:
void local_irq_restore(unsigned long flags);
void local_irq_enable(void);
2.顶半部和底半部
中断处理的一个主要问题是怎样在处理例程内完成耗时的任务。响应一次设备中断需要完成一定数量的工作,但是中断处理例程需要尽快结束而不能使中断阻塞的时间过长。Linux通过将中断处理例程分成两部分来解决这个问题。称为顶半部的部分,是实际响应中断的例程,也就是request_irq注册的中断例程。而所谓的底半部是一个被顶半部调度,并在稍后更安全的时间内执行的例程。顶半部和底半部最大的区别是底半部运行的时候所有的中断都是打开的。
实现底半部的机制一般有tasklet和工作队列。
tasklet
tasklet是一个可以在由系统决定的安全时刻在软件中断上下文被调度运行的特殊函数。tasklet可以确保和第一调度它们运行的函数运行在同样的CPU上。
工作队列
一般我们使用系统默认的工作队列作为底半部的进程。但如果我们的驱动程序有特殊的延迟需求(或者可能在工作队列函数中长时间休眠),则应该创建我们自己的专用工作队列。
三、中断共享
安装共享的处理例程
共享中断也是通过request_irq安装的,不同点如下:
i 请求中断时,必须指定flags参数中的SA_SHIRQ位。
ii dev_id参数必须是唯一的。
request_irq成功的条件是:第一,中断信号线空闲。第二,任何已经注册了该中断信号线的处理例程也标识了IRQ是共享的。
驱动中断处理
最新推荐文章于 2024-01-04 14:43:31 发布