博客
关于我
6.分析request_irq和free_irq函数如何注册注销中断(详解)
阅读量:434 次
发布时间:2019-03-06

本文共 5537 字,大约阅读时间需要 18 分钟。

request_irq和free_irq的使用分析

1. request_irq的功能分析

request_irq 是内核中用来注册中断服务函数的重要函数。它位于 kernel/irq/management.c 中,函数原型如下:

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id);

参数说明

  • unsigned int irq:要注册的中断号,例如外部中断0对应的号码是16,定义在 mach/irqs.h 中。
  • irq_handler_t handler:要注册的中断服务函数,即 (irq_desc + irq)->action->handler。
  • unsigned long irqflags:触发中断的参数,例如边沿触发,定义在 linux/interrupt.h 中。
  • *const char devname:中断程序的名字,可以通过 cat /proc/interrupt 查看。
  • *void dev_id:传入中断处理程序的参数。注册共享中断时不能为 NULL,因为卸载时需要这个参数。
  • 1.1 request_irq的代码解析

    request_irq 函数主要完成以下步骤:

  • 分配并初始化一个 irqaction 结构体。
  • 将参数赋给该结构体中的各个成员。
  • 调用 setup_irq 函数,将 action 加入中断描述符的 action 链表中。
  • 代码实现如下:

    int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) {    struct irqaction *action;    if (!action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC)) {        return -ENOMEM;    }    action->handler = handler;    action->flags = irqflags;    cpus_clear(action->mask);    action->name = devname;    action->next = NULL;    action->dev_id = dev_id;    select_smp_affinity(irq);    return setup_irq(irq, action);}

    1.2 setup_irq的功能分析

    setup_irq 是 request_irq 的一个辅助函数,主要负责将 action 加入中断描述符的 action 链表中,并初始化中断引脚。

    代码实现如下:

    int setup_irq(unsigned int irq, struct irqaction *new) {    struct irq_desc *desc = irq_desc + irq;    struct irqaction *old = &desc->action;    unsigned int shared = 0;    if (old) {        if (((old->flags & new->flags) & IRQF_SHARED) ||            ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {            shared = 1;        } else {            old_name = old->name;            goto mismatch;        }        if (config_intx) {            do {                old = *p;            } while (old);        }        shared = 1;    }    *p = new;    if (!shared) {        if (desc->chip && desc->chip->set_type) {            desc->chip->set_type(irq, new->flags & IRQF_TRIGGER_MASK);        } else {            printk(KERN_WARNING "No IRQF_TRIGGER set_type function for IRQ %d (%s)\n", irq, desc->chip ? desc->chip->name : "unknown");        }        if (!(desc->status & (IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS))) {            desc->depth = 0;            desc->status &= ~IRQ_DISABLED;            if (desc->chip->startup) {                desc->chip->startup(irq);            } else {                desc->chip->enable(irq);            }        } else {            desc->depth = 1;        }    }}

    1.3 中断引脚的初始化

    通过 setup_irq 函数,中断引脚的初始化主要通过 desc->chip->set_type 方法完成。以外部中断0为例,函数 s3c_irqext_type 会根据中断类型设置相应的寄存器模式。

    代码实现如下:

    unsigned int s3c_irqext_type(unsigned int irq, unsigned int type) {    void __iomem *extint_reg;    void __iomem *gpcon_reg;    unsigned long gpcon_offset, extint_offset;    if ((irq >= IRQ_EINT0) && (irq < IRQ_EINT3)) {        gpcon_reg = S3C2410_GPFCON;        extint_reg = S3C24XX_EXTINT0;        gpcon_offset = (irq - IRQ_EINT0) * 2;        extint_offset = (irq - IRQ_EINT0) * 4;    } else if (...) {        // 其他中断类型的处理    }    value = __raw_readl(gpcon_reg);    value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);    switch (type) {        case IRQT_NOEDGE:            printk(KERN_WARNING "No edge setting!\n");            break;        case IRQT_RISING:            newvalue = S3C2410_EXTINT_RISEEDGE;            break;        case IRQT_FALLING:            newvalue = S3C2410_EXTINT_FALLEDGE;            break;        case IRQT_BOTHEDGE:            newvalue = S3C2410_EXTINT_BOTHEDGE;            break;        case IRQT_LOW:            newvalue = S3C2410_EXTINT_LOWLEV;            break;        case IRQT_HIGH:            newvalue = S3C2410_EXTINT_HILEV;            break;        default:    }    value = __raw_readl(extint_reg);    value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);    __raw_writel(value, extint_reg);    return 0;}

    2. free_irq的功能分析

    free_irq 是用来卸载中断服务函数的函数,位于同一文件中,函数原型如下:

    void free_irq(unsigned int irq, void *dev_id);

    2.1 free_irq的代码解析

    free_irq 函数主要完成以下步骤:

  • 检查当前中断是否被占用。
  • 找到并释放与 dev_id 对应的中断 action。
  • 调用 chip->release 方法,释放中断资源。
  • 更新中断描述符的状态,并关闭或禁用中断。
  • 代码实现如下:

    void free_irq(unsigned int irq, void *dev_id) {    struct irq_desc *desc = irq_desc + irq;    struct irqaction **p;    unsigned long flags;    WARN_ON(in_interrupt());    if (irq >= NR_IRQS) {        return;    }    spin_lock_irqsave(&desc->lock, flags);    p = &desc->action;    for (;;) {        struct irqaction *action = *p;        if (!action) {            spin_unlock_irqrestore(&desc->lock, flags);            return;        }        if (action->dev_id != dev_id) {            *p = action->next;            continue;        }        *p = action->next;        if (desc->chip->release) {            desc->chip->release(irq, dev_id);        }        if (!desc->action) {            desc->status |= IRQ_DISABLED;            if (desc->chip->shutdown) {                desc->chip->shutdown(irq);            } else {                desc->chip->disable(irq);            }        }        spin_unlock_irqrestore(&desc->lock, flags);        unregister_handler_proc(irq, action);        synchronize_irq(irq);        if (action->flags & IRQF_SHARED) {            handler = action->handler;        }        kfree(action);        return;    }    printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);    spin_unlock_irqrestore(&desc->lock, flags);    return;}

    2.2 free_irq的卸载流程

  • 找到当前中断的 action 链表头。
  • 遍历 action 链表,找到与 dev_id 匹配的 action。
  • 释放该 action 对应的中断资源。
  • 更新中断描述符的状态,关闭或禁用中断。
  • 通过以上分析,可以清晰地了解 request_irq 和 free_irq 的工作原理,以及如何在内核中注册和卸载中断服务函数。

    转载地址:http://zqiyz.baihongyu.com/

    你可能感兴趣的文章
    no session found for current thread
    查看>>
    No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
    查看>>
    NO.23 ZenTaoPHP目录结构
    查看>>
    no1
    查看>>
    NO32 网络层次及OSI7层模型--TCP三次握手四次断开--子网划分
    查看>>
    NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
    查看>>
    Node JS: < 一> 初识Node JS
    查看>>
    Node Sass does not yet support your current environment: Windows 64-bit with Unsupported runtime(72)
    查看>>
    Node-RED中使用JSON数据建立web网站
    查看>>
    Node-RED中使用json节点解析JSON数据
    查看>>
    Node-RED中使用node-random节点来实现随机数在折线图中显示
    查看>>
    Node-RED中使用node-red-browser-utils节点实现选择Windows操作系统中的文件并实现图片预览
    查看>>
    Node-RED中使用node-red-contrib-image-output节点实现图片预览
    查看>>
    Node-RED中使用node-red-node-ui-iframe节点实现内嵌iframe访问其他网站的效果
    查看>>
    Node-RED中使用Notification元件显示警告讯息框(温度过高提示)
    查看>>
    Node-RED中实现HTML表单提交和获取提交的内容
    查看>>
    Node-RED中通过node-red-ui-webcam节点实现访问摄像头并截取照片预览
    查看>>
    node-request模块
    查看>>
    Node.js 8 中的 util.promisify的详解
    查看>>
    Node.js 函数是什么样的?
    查看>>