首先说下如果在裸机的情况下硬件中断是如何到来的:
首先中断有内部中断和外部中断两种,中断一共有64个中断源
1:内部中断的中断银角是直接和VIC(向量中断控制器)相连的,一个中断占用一个中断源,比如:wdt、网卡等设备
程序可以直接通过中断控制器中存放的中断处理函数来执行,因为某个内部中断号产生的源头是唯一的,而外部中断不同
2:由于外部中断比较多,除了内部中断之后的中断源不足以提供给外部中断,所以外部中断采用两极架构外加中断程序内部判断的方法,
来确定是来的那个中断。
首先:外部中断设备的银脚连接到二级的控制器上,二级控制器上也有mask和pending,这个对应于每一个外部中断设备
然后:二级控制器,通过一个银脚连接到VIC,如果二级控制器上收到中断,连带给VIC发送中断,这时候执行中断处理函数
最后:在中断处理函数里,通过读取二级控制器里的位来判断是那个设备发出的中断并且执行相应的处理函数
中断有两种方式相应:
1:通过向量的方法,发生中断pc就指向0x18,然后通过b汇编指令跳转到中断处理函数,然后读取VIC的寄存器确定中断号并且将PC指向中断处理函数,这个过程由认为处理(自己写函数)
2:通过协处理器来执行中断处理函数,全自动的,设置CP15的VE位
***:为硬件提供服务的两种方式:中断方式,轮询方式(USB设备是轮询)
I2C:两总线,一根提供时序,一根提供数据,使用的是轮询方法
这就是在裸机下的中断工作的大体原理,内核的对这些底层的细节具体如下:
内核为每个中断设置了一个中断号(包括外部中断和内部中断):
内核代码的头文件:
include/linux
arch/arm/include/asm
arch/arm/mach-s3c6410 ---->特定cpu所特有的头文件
arch/arm/plat-s3c --->三星CPU有特有的头文件
arch/arm/plat-s3c64xx --->三星CPU中某型号CPU所特有的头文件
在3.0之后的内核,三星的东西统一放在arch/arm/plat-sansung;
;
arch/arm/plat-s3c64xx/include/plat/irqs.h,这个头文件里存放着每个设备对应的中断号
#include
中断号分布如下:
0~15: 保留。为可能连接的ISA设备准备 ISA是早期的 并行设备,PCI也为并行设备,但是现在高速的PCI-E都是串行的
16~31: 分配给6410的4个UART。每个uart各分配4个
32~95:为6410的64组中断源每组分配了一个中断号,完全按照6410手册中的中断源顺序分配
96~100: 为5个硬件定时器每人分配一个中断号
101~128: 为外部中断的组0分配的中断号(共28个),第0组
129~227: 为外部中断组1~9分配的中断号(共99个)
常量NR_IRQS用于表示中断号的总数量,对应6410来说,是228
对于6410来说,外部中断组0的中断号,可以利用宏S3C_EINT(X)来获得
3.linux的中断处理
核心结构体:
(1)irq_desc
定义在
对应一个中断号。linux内核在启动时分配了一个irq_desc的数组,数组中共有NR_IRQS个成员。每个irq_desc中记录对应中断的各类信息,比如中断的处理函>数,中断的发生次数等。
irq_desc由内核负责准备。
(2)irqaction
定义在
每个irqaction用于封装一个中断处理函数。结构体由驱动人员负责分配。
irqaction中包含中断号;中断处理函数指针;中断的执行标志;中断名等
(3)irq_handler_t
定义在,如下:
irqreturn_t (*irq_handler_t)(int, void *);
中断处理函数。由驱动负责实现,记录在irqaction中。
irqreturn_t只有两个值,IRQ_NONE/IRQ_HANDLED。如果中断不是由本设备引起的,则返回IRQ_NONE,否则返回IRQ_HANDLED。
函数参数irq为中断号,void *为传递给中断处理函数的参数,对应irqaction->dev_id。
驱动人员在设计中断处理函数时,要遵循的要求是:
(1)可嵌套不可重入
中断没有优先级,进程有优先级。中断会被别的中断打断,所以中断可以嵌套,但是同一个中断不能同时来两次,这样会导致重入
(2)不能睡眠
不能使用休眠的函数,内存分配GFP要使用GFP_ATOMIC标志位,如果使用GFP_KERNEL则会调用swap线程进行将内存到swap分区的掉换
(3)如果硬件有中断的状态寄存器,软件要负责清除中断的标志位。一般来说,如果不清除标志位,设备无法再次产生中断
清楚硬件位一般有:写1,在写一次,或者设置其他寄存器这三种方法来清楚
由于硬件中断产生的随即值:
xxd /dev/randon //真随即数
xxd /dev/vrandon //伪随即数
使用方法:
通过 S3C_EINT(2) 将芯片手册上的中断号转换成内核识别的中断号
设置中断处理标记:
flags = IRQF_SHARED |
这个中断号是共享的,一个中断号下可以挂在多个设备,只要有一个中断来,就会遍历所有设备,通过设备的寄存器来确定是否真的有中断到来
IRQF_SAMPLE_RANDOM |
IRQF_TRIGGER_FALLING; 中断是下降沿有效
//IRQF_TRIGGER_RISING; 上升沿有效
//IRQF_TRIGGER_LOW; 低电平有效
ret = request_irq(S3C_EINT(2), 设置中断号
key_service, 设置中断处理函数
flags, 设置中断属性
keys[i]->irq_name, 设置中断名称
keys[i]); 设置私有数据,将所为参数传到中断处理函数里
失败返回非0值,要检测
free_irq(irq, dev_id);来释放一个中断,irq是中断号,devid是私有设备数据
static irqreturn_t key_service(int irq, void *dev_id)
{
return IRQ_HANDLED; /* IRQ_NONE */
}
key_test02.rar
阅读(2563) | 评论(0) | 转发(0) |