首先需要了解一下中断的概念:一个“中断”仅仅是一个信号,当硬件需要获得处理器对它的关注时,就可以发送这个信号。内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表。
模块在使用中断前要先请求一个中断通道(或中断请求IRQ),然后在使用后释放该通道。用到的API就是request_irq()以及free_irq()。注意在调用request_irq()和free_irq()的时机最好是在设备第一次打开和最后一次关闭之后。
对于中断处理例程来讲,它的一个典型的任务就是:如果中断通知进程所等待的事件已经发生,比如新的数据到达就会唤醒在该设备上休眠的进程。无论是快速还是慢速处理例程,程序员都应该编写执行事件尽可能短的处理例程。如果需要执行一个长时间的计算任务,做好的办法就是使用上下半部处理机制,以便让工作在更安全的时间里调度计算任务。
上半部的功能是响应中断。当中断发生时,它就把设备驱动程序中中断处理例程的下半部挂到设备的下半部执行队列中去,然后继续等待新的中断到来。这样一来,上半部的执行速度就会很快,它就可以接受更多它负责的设备所产生的中断了。上半部之所以快,是因为它是完全屏蔽中断的,如果它没有执行完,其他中断就不能及时地处理,只能等到这个中断处理程序执行完毕以后。所以要尽可能多的对设备产生的中断进行服务和处理,中断处理程序就一定要快。
下半部的功能是处理比较复杂的过程。下半部和上半部最大的区别是可中断,而上半部却不可中断。下半部几乎完成了中断处理程序所有的事情,因为上半部只是将下半部排到了它们所负责的设备中断的处理队列中去,然后就不做其它的处理了。下半部所负责的工作一般是查看设备以获得产生中断的事件信息,并根据这些信息(一般通过读设备上的寄存器得来)进行相应的处理。下半部是可中断的,所以在运行期间,如果其它设备产生了中断,这个下半部可以暂时的中断掉,等到那个设备的上半部运行完了,再回头运行这个下半部。
这上面大多数都是我们在查阅资料和听老师讲课获取的知识内容但是具体是如何实现的呢?
也许我们也知道tasklet和work_queue。知道这两个是完成下半部的。在具体的过程中我们将如何实现呢?
此处就是通过创建工作队列的方式我们把初始化的操作都放在irq之前完成,在irq_handler()中将具体的工作提交到工作队列中。使用的API为queue_work()。具体的细节问题希望读者能够查阅资料自行完成。