Linux内核API irq_set_chip

irq_set_chip函数功能描述:此函数是为irq_desc数组中对应下标为irq的元素设定irq_chip的值,如果传入的参数chip为NULL,则使用系统定义好的no_irq_chip为它赋值:如果传入的参数chip不为NULL,则用传入的参数赋值。在赋值之前函数会调用函数irq_chip_set_defaults( )对传入的参数chip进行相应的设置处理,处理完之后把参数chip赋值给irq_desc数组中的变量的irq_chip。

irq_set_chip文件包含

#include<linux/irq.h>

函数定义:

在内核源码中的位置:linux-3.19.3/kernel/irq/chip.c

函数定义格式:

int irq_set_chip(unsigned int irq, struct irq_chip *chip)

irq_set_chip输入参数说明

参数irq是设备对应的中断编号,对应数组irq_desc中元素的下标,此数组的大小为16640。

参数chip是一个struct irq_chip型的结构体变量,是对应的硬件中断描述符的irq_chip字段的值,定义见文件linux-3.19.3/include/linux/irq.h如下:

struct irq_chip {
    const char     *name;
    unsigned int  (*irq_startup)(struct irq_data *data);
    void             (*irq_shutdown)(struct irq_data *data);
    void             (*irq_enable)(struct irq_data *data);
    void             (*irq_disable)(struct irq_data *data);

    void             (*irq_ack)(struct irq_data *data);
    void             (*irq_mask)(struct irq_data *data);
    void             (*irq_mask_ack)(struct irq_data *data);
    void             (*irq_unmask)(struct irq_data *data);
    void             (*irq_eoi)(struct irq_data *data);

    int              (*irq_set_affinity)(struct irq_data *data, const struct
                    cpumask *dest, bool force);
    int              (*irq_retrigger)(struct irq_data *data);
    int              (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
    int              (*irq_set_wake)(struct irq_data *data, unsigned int on);
    void             (*irq_bus_lock)(struct irq_data *data);
    void             (*irq_bus_sync_unlock)(struct irq_data *data);

    void             (*irq_cpu_online)(struct irq_data *data);
    void             (*irq_cpu_offline)(struct irq_data *data);

    void             (*irq_suspend)(struct irq_data *data);
    void             (*irq_resume)(struct irq_data *data);
    void             (*irq_pm_shutdown)(struct irq_data *data);

    void             (*irq_calc_mask)(struct irq_data *data);

    void             (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
    int              (*irq_request_resources)(struct irq_data *data);
    void             (*irq_release_resources)(struct irq_data *data);

    void             (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
    void             (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

    unsigned long flags;
};

如果传入的参数chip为NULL,则系统用no_irq_chip进行初始化,no_irq_chip的定义见文件linux-3.19.3/kernel/irq/dummychip.c,如下:

struct irq_chip no_irq_chip = {
    .name           = "none",
    .irq_startup  = noop_ret,
    .irq_shutdown = noop,
    .irq_enable    = noop,
    .irq_disable  = noop,
    .irq_ack       = ack_bad,
};

irq_set_chip返回参数说明

此函数的返回结果是int型变量,可能的取值是0、-22,如果返回0说明设置字段chip的值成功,如果返回-22说明设置字段chip的值失败,设置失败的原因是与irq对应的数组中的元素不存在。

irq_set_chip实例解析

编写测试文件:irq_set_chip.c头文件引用及全局变量定义:

#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static int irq=2;     //中断号定义,可更改1000进行错误验证

中断处理函数定义及中断线程处理函数定义:

// 自定义中断处理函数
static irqreturn_t irq_handler(int irq, void *dev_id)
{
    printk("the irq is :%d\n", irq);  //中断号
    printk("in the interrupt handler function\n");
    return IRQ_WAKE_THREAD;
}

// 自定义中断线程处理函数
static irqreturn_t irq_thread_fn(int irq, void *dev_id)
{
    printk("the irq is :%d\n", irq);  //对应的中断号
    printk("in the thread handler function\n");
    return IRQ_HANDLED;
}

模块加载函数定义及验证函数调用:

static int __init irq_set_chip_init(void)
{
    int result=0;
    int result1=0;
    printk("into irq_set_chip_init\n");

    /*动态申请中断*/
    result=request_threaded_irq(irq, irq_handler, irq_thread_fn, IRQF_DISABLED, "A_NEW_DEVICE", NULL);
    result1=irq_set_chip(irq, NULL);      //调用函数irq_set_chip()irq是对应的中断号
    printk("the request_threaded_irq result is: %d\n", result);
                                          //显示函数request_threaded_irq( )结果
    printk("the irq_set_chip result is: %d\n", result1);
                                          //显示函数irq_set_chip( )返回结果
    printk("out irq_set_chip_init\n");
    return 0;
}

模块退出函数定义:

static void __exit irq_set_chip_exit(void)
{
    free_irq(irq, NULL);       //释放申请的中断
    printk("Goodbye irq_set_chip_exit\n");
    return;
}

模块加载、退出函数调用:

module_init(irq_set_chip_init);
module_exit(irq_set_chip_exit);

实例运行结果及分析:

当设置的中断号为2时,编译模块,执行命令insmod irq_set_chip.ko插入内核模块,然后输入dmesg -c查看内核输出信息,出现如图A所示的结果。

Linux内核API irq_set_chip

在卸载模块之前输入命令cat /proc/interrupts查看文件/proc/interrupts的内容,出现如图B所示的结果。

Linux内核API irq_set_chip

如果将函数的第一个参数irq设置为1000,插入模块,会出现如图C所示的结果。

Linux内核API irq_set_chip

结果分析:

由图A函数irq_set_chip( )的返回结果可以判断设置中断描述符中的irq_chip字段成功;图B中中断号2对应的信息可以看到函数irq_set_chip( )执行之后的效果,第六列的内容为none,如果没有函数irq_set_chip( ),此部位的内容应该为IO-APIC-,这是因为传递给函数的第二个参数为NULL,此时中断描述符中的irq_chip字段被设置为no_irq_chip变量的值。

C中的显示信息是函数执行失败时的一种情况,显示内核的调试信息,因为传递的参数irq的值超过了数组irq_desc的范围。

赞(1)
未经允许不得转载:极客笔记 » Linux内核API irq_set_chip
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址