博客
关于我
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/

    你可能感兴趣的文章
    NIFI汉化_替换logo_二次开发_Idea编译NIFI最新源码_详细过程记录_全解析_Maven编译NIFI避坑指南001---大数据之Nifi工作笔记0068
    查看>>
    NIFI集群_内存溢出_CPU占用100%修复_GC overhead limit exceeded_NIFI: out of memory error ---大数据之Nifi工作笔记0017
    查看>>
    NIFI集群_队列Queue中数据无法清空_清除队列数据报错_无法删除queue_解决_集群中机器交替重启删除---大数据之Nifi工作笔记0061
    查看>>
    NIH发布包含10600张CT图像数据库 为AI算法测试铺路
    查看>>
    Nim教程【十二】
    查看>>
    Nim游戏
    查看>>
    NIO ByteBuffer实现原理
    查看>>
    Nio ByteBuffer组件读写指针切换原理与常用方法
    查看>>
    NIO Selector实现原理
    查看>>
    nio 中channel和buffer的基本使用
    查看>>
    NIO三大组件基础知识
    查看>>
    NIO与零拷贝和AIO
    查看>>
    NIO同步网络编程
    查看>>
    NIO基于UDP协议的网络编程
    查看>>
    NIO笔记---上
    查看>>
    NIO蔚来 面试——IP地址你了解多少?
    查看>>
    NISP一级,NISP二级报考说明,零基础入门到精通,收藏这篇就够了
    查看>>
    NISP国家信息安全水平考试,收藏这一篇就够了
    查看>>
    NIS服务器的配置过程
    查看>>
    Nitrux 3.8 发布!性能全面提升,带来非凡体验
    查看>>