【linux】设备驱动动态中断申请

来源:互联网 发布:js jc jk jd 编辑:程序博客网 时间:2024/05/29 15:53

<!--@page { margin: 0.79in }P { margin-bottom: 0.08in }-->

Kernel Korner - Dynamic InterruptRequest Allocation for Device Drivers

 

 

From Issue #132

April 2005

Mar 01, 2005 By Dr B. Thangaraju

inSoftware

 

中断是处理器和设备沟通的大门。在设备驱动开发中,申请中断请求线(后文简称中断)以及如何处理中断是至关重要的。中断的数量是有限的,共享中断可以让处理器访问更多的设备。尝试申请已经使用的中断会破坏系统。这篇介绍了中断的使用以及如何在一个字符设备中使用中断。

 

中断是一个硬件机制,可以使设备和处理器交互。

 

2.6内核中,Linux中,如果一个进程在kernelmode,如果任意一个高优先级的进程到了ready-to-run的进程队列,低优先级的进程就不能在该高优先级的进程返回用户模式之前抢占。但是,一个中断可以使CPU转移注意力,即便进程在内核模式内执行。当一个中断发生时,CPU挂起当前的任务,执行一些中断相关的代码。

 

每一个在计算机中的设备有一个设备控制器,当他需要CPU服务时,就会通过一个硬件引脚发出信号。这个硬件引脚和CPU的中断引脚相连。处理器中连接到控制器处理中断的引脚叫中断请求线(IRQInterrupt requestline)。CPU有若干个这样的引脚。在现代操作系统中,有意个可编程的中断控制器(PICprogrammableinterruptcontroller)来管理处理器和各种设备控制器之间的IRQIRQ是有限的,Linux通过共享中断线来增加可以产生中断的设备。

 

CPU执行一个进程,一个设备发送中断到CPU,比如准备传输数据。当一个中断到来,CPU立即保存当前kernelmode stackprogramcounter,然后执行对应的中断服务(ISRinterruptserviceroutine)。一个ISR是一个处于kernel中的函数,用来处理中断的一些请求,比如移动数据等等。执行完ISRCPU就恢复到之前的进行,然后接着执行。

 

设备驱动程序是一个在kernel中的软件模块,等到来自应用程序的请求。当一个程序需要从设备中读取数据,对应的设备驱动器就会立即打开,然后对应的设备就会被打开准备读取。如果系统在等待一个慢速设备,就不能做其他事情。为了避免等待,kernel把等待的工作交给设备控制器,然后恢复执行之前的进程。当读完毕之后,设备通过中断通知CPUCPU执行相应的ISR

 

Interrupt classification

 

中断分为两类,同步和异步。同步中断是CPUcontrolunit在执行指令时产生的。控制单元在终止指令之后产生一个中断,就命名为同步。异步中断是硬件按照CPU时钟在任意时间产生的。在Intel系统中,同步中断被称之为异常,异步中断称之位中断。中断通过一个无符号的one-byte整数表示,称之为向量,范围是0~255。最开始的32个向量(031)用于异常和不可屏蔽中断,3247是可屏蔽中断,由IRQs(0-15)引起。最后的48~255被标记为软件中断。

IRQ Allocation

通过/proc/interrupt可以显示当前注册的中断。比如:

CPU0 CPU1

0: 112559049 0 IO-APIC-edge timer

1: 143195 0 IO-APIC-edge i8042

8: 1 0 IO-APIC-edge rtc0

9: 36 0 IO-APIC-fasteoi acpi

12: 2134767 0 IO-APIC-edge i8042

14: 430047 0 IO-APIC-edge ata_piix

15: 318204 0 IO-APIC-edge ata_piix

16: 64752 0 IO-APIC-fasteoi i915@pci:0000:00:02.0

17: 0 0 IO-APIC-fasteoi eth0

18: 0 0 IO-APIC-fasteoi r852, mmc0

NMI: 0 0 Non-maskable interrupts

LOC: 16015255 66885938 Localtimer interrupts

SPU: 0 0 Spuriousinterrupts

PMI: 0 0 Performance monitoring interrupts

PND: 0 0 Performance pending work

RES: 9789301 11248394 Rescheduling interrupts

CAL: 69042 74498 Functioncall interrupts

TLB: 96130 208644 TLBshootdowns

TRM: 0 0 Thermalevent interrupts

THR: 0 0 ThresholdAPIC interrupts

MCE: 0 0 Machinecheck exceptions

MCP: 216 214 Machinecheck polls

ERR: 7

MIS: 0

第一列是中断号,第二列是系统开机以来产生的中断次数。第三列是PIC相关,第四列是与中断相关的设备名字。

 

最简单的动态加载一个设备驱动的办法是,首先找到一个没有用的IRQrequest_irq用来申请设备的中断。

Int request_irq (unsigned int irq,

irq_handler_t handler,

unsigned long flags,

const char *device, void*dev_id);

第一个参数是中断号,我们想从系统中申请的中断号。

Handler是中断处理函数。

Flags是中断标识。SA_INTERRUPT是设置快速中断,SA_SHIRQ是设置共享中断。SA_PROBE是用该中断来probe一个设备。SA_RANDOM是系统随机数生成器的种子。

Device是设备名字。

dev_id是设备id,一个指向structdevice的指针。

 

request_irq如果成功,返回0,如果失败,就返回-EBUSY

 

free_irq用来释放中断:

free_irq(unsigned int irq, void *dev_id);

ISR会在中断发生的时候调用。内核维护了一张表,表中是中断处理的地址,也就是中断向量表。当一个中断发生,处理器检查中断向量表中的地址,然后执行。