remove_irq函数功能描述:此函数用于卸载IRQ链表中的与输入参数相对应的irqaction描述符。
功能实现过程:函数通过调用函数__free_irq( )实现其功能,传给__free_irq( )的参数是irq与act->dec_id,函数__free_irq( )根据参数irq找到数组irq_desc中对应的元素desc,如果不存在则返回NULL;如果存在则根据dev_id找到对应的irqaction标识符,如果不存在则返回NULL,如果存在则进行一定的操作,将其从IRQ链表中删除,最后返回该irqaction标识符。
remove_irq文件包含
#include<linux/irq.h>
remove_irq函数定义
在内核源码中的位置:linux-3.19.3/kernel/irq/manage.c
函数定义格式:
void remove_irq(unsigned int irq, struct irqaction *act)
remove_irq输入参数说明
参数unsigned int irq是对应的中断号,相应的取值是0~16640,系统已用的是0~31,其中编号IRQ9、IRQ10、IRQ15系统保留,32~16640是用于用户定义的中断。
参数act是与系统对应的一个irqaction标识符,是一个struct irqaction类型的结构体指针,其定义见文件linux-3.19.3/include/linux/interrupt.h,如下:
struct irqaction {
irq_handler_t handler;
void *dev_id;
void __percpu *percpu_dev_id;
struct irqaction *next;
irq_handler_t thread_fn;
struct task_struct *thread;
unsigned int irq;
unsigned int flags;
unsigned long thread_flags;
unsigned long thread_mask;
const char *name;
struct proc_dir_entry *dir;
} ____cacheline_internodealigned_in_smp;
其中:
- 字段handler是一个函数指针,代表中断处理函数,此函数的返回值类型是irq_handler_t类型的变量,可能的取值是IRQ_NONE 、IRQ_HANDLED、IRQ_WAKE_THREAD。
- 字段dev_id保存与此中断标识符相对应的设备标识符,用于识别设备。
- 字段percpu_dev_id为设备识别符,用于识别设备。
- 字段next指向中断向量链表中的下一个中断标识符。
- 字段thread_fn是一个函数指针,指向中断线程处理函数,返回值类型与字段handler的返回值类型相同。
- 字段thread是一个任务描述符指针,指向与此中断线程对应的线程。
- 字段irq对应此中断标识符对应的中断号。
- 字段f lags是用来标识中断的类型,其定义见文件linux-3.19.3/include/linux/interrupt.h,可能的取值为:
#define IRQF_DISABLED 0x00000020 //中断使能
#define IRQF_SHARED 0x00000080 //设备共享
#define IRQF_PROBE_SHARED 0x00000100 //错序共享中断
#define __IRQF_TIMER 0x00000200 //时钟中断
#define IRQF_PERCPU 0x00000400 //CPU中断
#define IRQF_NOBALANCING 0x00000800 //中断平衡使能
#define IRQF_IRQPOLL 0x00001000 //中断轮询检测,用于设备共享的中断
#define IRQF_ONESHOT 0x00002000 //将中断保持不可用状态,直到中断处理函数结束
#define IRQF_NO_SUSPEND 0x00004000 //挂起期间不让中断保持不可用状态
// 强制中断处于重新开始状态即使设置了IRQF_NO_SUSPEND状态
#define IRQF_FORCE_RESUME 0x00008000
#define IRQF_NO_THREAD 0x00010000 //不可中断线程状态
#define IRQF_EARLY_RESUME 0x00020000 //提前恢复IRQ而不是在设备恢复期间
#define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
// 复合定义
- 字段thread_f lags是一个线程标志,标示一个线程所处的状态。
- 字段thread_mask是对应的CPU掩码,表示此中断所在的CPU编号。
- 字段name是与此中断标识符相对应的设备名。
- 字段dir是一个目录入口指针,指向在文件夹/proc/irq中与此中断标识符所对应的中断号相对应的文件夹。
remove_irq返回参数说明
此函数不返回任何类型的数据。
remove_irq实例解析
编写测试文件:remove_irq.c
头文件引用及全局变量定义:
#include <linux/interrupt.h>
#include<linux/irq.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static int irq=11; //中断号定义
/*声明一个变量,中断号为10,中断处理函数是myhandler( ),中断的类型是IRQF_DISABLED类型的,
中断对应的设备名是A_New_Device,设备编号是NULL(即设备不真实存在)*/
static struct irqaction act =
{
.irq=11,
.handler=irq_handler,
.flags=IRQF_DISABLED,
.name="A_New_Device",
.dev_id=NULL
};
中断处理函数定义:
// 自定义中断处理函数,在此只是起显示作用
static irqreturn_t irq_handler(int data, void *dev_id)
{
printk("the data is :%d\n", data);
printk("in the interrupt handler function\n");
return IRQ_NONE;
}
模块加载函数定义:
static int __init remove_irq_init(void)
{
int result=0;
struct irqaction *myact=&act;
printk("into remove_irq_init\n");
result=request_irq(myact->irq, myact->handler, myact->flags, myact-
>name, myact->dev_id); //申请中断
printk("the result is: %d\n", result); //显示申请结果
printk("out remove_irq_init\n");
return 0;
}
模块退出函数定义:
static void __exit remove_irq_exit(void)
{
printk("remove the irq in the remove_irq_exit function\n");
remove_irq(irq, &act); //调用函数remove_irq( ), irq是对应的中断号,act是对应的中断变量
printk("Goodbye remove_irq\n");
return;
}
模块加载、退出函数调用:
module_init(remove_irq_init);
module_exit(remove_irq_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod remove_irq.ko,然后先后输入命令dmesg -c查看内核输出信息,输入命令cat /proc/interrupts查看文件/proc/interrupts内容,会出现如图A
所示的结果。
执行命令rmmod remove_irq.ko卸载内核模块,然后输入命令cat /proc/interrupts查看文件/proc/interrupts的内容,出现如图B
所示的结果。
结果分析:
由图A
可以判断中断申请成功,函数request_irq( )的返回结果和文件/proc/interrupts的内容都可以得出此结论;图B
可以判断申请的中断被删除,从文件/proc/interrupts的内容可以看出虽然中断号11的记录还存在,但是对应的设备文件名为空,已经不是“A_New_Device”,说明函数remove_irq( )能够将与输入参数相关的中断从IRQ链表中删除。