《Linux设备驱动程序》——中断处理

  • Post author:
  • Post category:linux


一、准备并口(略)

二、安装中断处理例程

一)、相关简介

1、内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表。模块在使用中断前要先请求一个中断通道(或者中断请求IRQ),然后在使用后释放该通道。

2、下列在头文件<linux/sched.h>中声明的函数实现了共享中断的接口:

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);

1)、unsigned  int  irq:这是要申请的中断号。

2)、irqreturn_t  (*handler)(int,  void  *,  struct  pt_regs  *):这是要安装的中断中断处理指针。

3)、unsigned  long  flags:这是一个与中断管理有关的位掩码选项。

I、SA_INTERRUPT。

II、SA_SHIRQ。

III、SA_SAMPLE_RANDOM。

4)、const  char  *dev_name:传递给request_irq的字符串,用来在/proc/interrupts中显示中断的拥有者。

5)、void  *dev_id:这个指针用于共享的中断信号线。

3、调用request_irq的正确位置应该是在设备第一次打开,硬件被告知产生中断之前。调用free_irq的位置是最后一次关闭设备,硬件被告知不用在中断处理器之后。这种技术

的缺点是必须为每个设备维护一个打开计数,这样我们就能知道什么时候可以禁用中断。

4、i386和x86_64体系架构定义了如下函数,用于查询某个中断线是否可用:

int  can_request_irq(unsigned  int  irq,  unsigned  long  flags);

1)、如果能够分配给定的中断,则函数返回非零值。

2)、注意,在调用can_request_irq和request_irq之间,始终可能发生一些事情来改变现状。

二)、/proc接口

1、当硬件的中断到达中断处理器时,一个内部计数器递增,这位检查设备是否按预期工作提供了一种方法。产生的中断报告显示在文件/proc/interrupts中。如果查看:

1)、第一列是IRQ号,其中明显缺少一些中断,说明文件只会显示那些已经安装了中断处理例程的中断。

2)、第二和第三列给出了已经发送到系统上每一个CPU的中断数量。

3)、最后两列给出了处理中断的可编程控制器信息,以及注册了中断处理例程的设备名称。

2、/proc/stat记录了一些系统活动的底层统计信号,包括(但不限于)从系统启动开始接收到的中断数量,stat文件的每行都以一个字符串开始,它是这行的关键字。

1)、第一个数是所有中断的总数,而其他的每个数代表一个单独的IRQ信号线,从中断0开始。

3、/proc/interrupts和/proc/stat的不同:

1)、/proc/stat依赖体系结构:字段的数量依赖于内核之下的硬件。

2)、/proc/interrupts不依赖体系结构。

三)、自动检测IRQ号

1、驱动程序初始化时,最迫切的问题之一就是如何决定设备将要使用哪条IRQ信号线。中断号的自动检测对于驱动程序可用性来说是一个基本要求。

1)、有些设备会简单“声明”它们它们要使用的中断。这样,驱动程序就可以通过从设备的某个I/O端口或者PC配置空间中读出一个状态来获得中断号。当目标设备有能力告诉

驱动程序它将使用的中断号时,自动检测IRQ号知识意味着探测设备,而不是需要额外的工作来探测中断。

2)、并不是所有的设备都对程序员很友好,自动检测可能还是需要做一些探测工作。

2、内核帮助下的探测

1)、Linux内核提供了一个底层设施来探测中断号。它只能在非共享中断的模式下工作。

unsigned  long  probe_irq_on(void);

int  probe_irq_off(unsigned  long);

I、主要在调用probe_irq_on之后启用设备上的中断,并在调用probe_irq_off之前禁用中断。

II、在probe_irq_off之后,需要处理设备上待处理的中断。

2)、探测是一项很耗时的任务。最好的办法就是只在模块初始化的时候探测中断信号线一次,这与是否在设备打开时或在初始化函数内安装中断处理例程无关。

3)、值得注意的是,在一些平台上,探测是没有必要的,因此前面的函数只是一些空的占位符。

3、DIY探测(略)

四)、快速和慢速处理例程

1、快速中断是那些很快被处理的中断,而处理慢速中断则会明显花费更长的时间。

2、在现代内核中,很多快速中断和慢速中断的区别已经消失。剩下的只有一个:快速中断(使用SA_INTERRUPT标志申请的中断)执行时,当前处理器上的其他所有中断都

被禁止。

3、在现代系统中,SA_INTERRUPT只是在少数几种特殊情况下使用。读者不应该使用SA_INTERRUPT标志,除非有足够必要的理由想要在其他中断被禁止的时候运行自己

的中断处理例程。

4、x86平台上中断处理的内幕(略)

三、实现中断处理接口

一)、相关简介

1、中断处理例程也是C程序,惟一特殊的地方就是处理例程是在中断时间内运行的。

2、中断处理例程的功能就是将相关中断接收的信息反馈给设备,并根据正在服务的中断的不同含义对数据进行相应的读和写。

1)、第一步通常要清除接口卡上的一个位,大多数硬件设备在它们的“interrupt-pending(中断挂起)”位被清除之前不会产生其他中断。此步骤不存在永恒规则,有些设备不

需要这个步骤。

2)、中断处理例程一个典型的任务就是:如果中断通知进程所等待的时间已经发生,就会唤醒该设备上的休眠进程。

3)、无论是快速还是慢速处理例程,程序员都应该编写执行时间尽可能短的处理例程。如果需要执行一个长时间的执行任务,最好的办法是使用tasklet或工作队列在更安全

的时间内调度计算任务。

3、研究书中相关代码

二)、处理例程的参数及返回

1、研究书中相关代码

2、宏IRQ_RETVAL的作用。

三)、启用和禁用中断

1、禁止单个中断

void  disable_irq(int  irq);

void  disable_irq_nosync(int  irq);

void  enable_irq(int  irq);

1)、调用这些函数中的任何一个都会更新可编程中断控制器中指定中断的掩码,因而就可以在所有处理器上禁止或启用IRQ。

2)、对这些函数的调用是可以嵌套的。

2、禁用所有中断

void  local_irq_save(unsigned  long  flags);

void  local_irq_disable(void);

3、打开所有中断

void  local_irq_restore(unsigned  long  flags);

void  local_irq_enable(void);

四、顶半部和底半部

一)、相关简介

1、顶半部和底半部的概念。

1)、顶半部是实际相应中断的例程,也就是调用request_irq注册的中断例程。

2)、底半部是一个被顶半部调度,并在稍后更安全的时间内执行的例程。

2、Linux实现底半部两种不同的机制:tasklet和工作队列。

二)、tasklet

1、tasklet是一个可以在由系统决定的安全时刻在软件中断上下文被调度运行的特殊函数。

1)、tasklet可以被多次调用运行,但tasklet的调度并不会积累。

2)、tasklet可以确保和第一次调用它们的函数运行在同样的CPU上。

2、必须使用宏DECLARE_TASKLET声明tasklet:

DECLARE_TASKLET(name,  function,  data);

3、short模块实例。

三)、工作队列

1、工作队列是在将来的某个时间,在某个特殊的工作者进程上下文中调用的一个函数。

2、short模块例程。

五、中断共享

一)、安装共享的处理例程

1、共享的中断也是通过request_irq安装的,但是有如下不同:

I、请求中断时,必须制定flags参数中的SA_SHIRQ位。

II、dev_id参数是唯一的。人恶化指向模块地址空间的指针都可以使用,但dev_id不能设置成NULL。

2、当请求一个中断时,如果满足一下条件之一,那么request_irq就会成功

I、中断信号线空闲。

II、任何已经注册了该中断信号线的处理例程也标识了IRQ是共享的。

3、如果在请求中断信号线之前需要探测设备的话,则内恶化不会有所帮助。对于共享的处理例程是没有探测函数可以利用的。仅当要使用的中断信号线处于空闲时,标准的探

测机制才能工作。

4、释放处理例程同样是通过执行free_irq来实现的。

5、使用共享处理例程需要注意:不能使用enable_irq和disable_irq。

三)、运行处理例程

1、short模块实例

四)、/proc接口和共享的中断

1、在系统上安装共享的中断处理例程不会对/proc/stat造成影响,但是,/proc/interrupts会有稍微改变。

六、中断驱动的I/O

1、如果与驱动程序管理的硬件之间的数据传输因为某种原因被延迟的话,驱动程序作者就应该实现缓冲。数据缓冲区有助于将数据的传送和接受与系统调用write和read分离

开来,从而提高系统的整体性能。

2、要正确进行中断驱动的数据传输,则要求硬件应该能按照下面的语义来产生中断:

1)、对于输入来说,当新的数据已经到达并且处理器准备好接收它们时,设备就中断处理器。实际执行的动作取决于设备使用的是I/O端口、内存映射,还是DMA。

2)、对于输出来说,当新的设备准备好新的数据或者对成功indeed数据进行应答时,就要发出中断。内存映射和具有DMA能力的设备,通常通过产生中断通知系统它们对缓

冲区的处理已经结束。

3、写缓冲示例(shortprint驱动程序)



版权声明:本文为Explorer_day原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。