当前位置: 首页 > ds >正文

linux kernel irq相关函数详解

在Linux内核驱动开发中,处理中断涉及一系列关键函数,正确使用这些函数对确保驱动的稳定性和性能至关重要。以下是disable_irqfree_irqplatform_get_irqrequest_irq等函数的详细解析,涵盖其功能、用法、注意事项及示例代码。


一、核心函数详解

1. request_irq:注册中断处理程序
  • 功能:申请中断线并绑定中断处理函数。

  • 函数原型

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

  • 参数

    • irq:中断号(通过platform_get_irq获取)。

    • handler:中断处理函数(如irq_handler_t类型)。

    • flags:中断标志(如IRQF_SHAREDIRQF_TRIGGER_RISING)。

    • name:中断名称(在/proc/interrupts中显示)。

    • dev_id:设备标识符(用于共享中断时的唯一标识)。

  • 返回值:成功返回0,失败返回错误码。

  • 示例

    
    ret = request_irq(irq_num, my_interrupt_handler, IRQF_SHARED, "my_device", dev);
    if (ret) {pr_err("Failed to request IRQ %d\n", irq_num);return ret;
    }

2. platform_get_irq:获取平台设备中断号
  • 功能:从设备树或平台资源中提取中断号。

  • 函数原型

    
    int platform_get_irq(struct platform_device *dev, unsigned int num);

  • 参数

    • dev:平台设备结构体指针。

    • num:中断资源索引(通常为0,表示第一个中断)。

  • 返回值:成功返回中断号,失败返回负数错误码。

  • 示例

    
    int irq = platform_get_irq(pdev, 0);
    if (irq < 0) {dev_err(&pdev->dev, "Failed to get IRQ\n");return irq;
    }

3. free_irq:释放中断资源
  • 功能:解除中断处理函数并释放中断线。

  • 函数原型

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

  • 参数

    • irq:中断号。

    • dev_id:与request_irq时一致的设备标识符。

  • 注意事项

    • 必须在驱动卸载(如remove函数)中调用。

    • 共享中断时,dev_id必须唯一匹配。

  • 示例

    
    free_irq(irq_num, dev);

4. disable_irq 与 enable_irq:禁用/启用中断
  • 功能:临时禁用或重新启用中断线。

  • 函数原型

    
    void disable_irq(unsigned int irq);
    void enable_irq(unsigned int irq);

  • 变体

    • disable_irq_nosync:立即禁用中断,不等待当前处理完成。

    • enable_irq:需与disable_irq成对调用。

  • 注意事项

    • 多次调用disable_irq需对应相同次数的enable_irq

    • 避免在中断上下文中调用disable_irq(可能导致死锁)。

  • 示例

    
    disable_irq(irq_num);
    // 执行关键操作(如修改共享数据)
    enable_irq(irq_num);


二、使用场景与流程

1. 驱动初始化(Probe函数)
  1. 获取中断号:通过platform_get_irq获取硬件中断号。

  2. 注册中断处理程序:调用request_irq绑定处理函数。

  3. 可选配置:设置中断触发方式(如边沿触发)或共享标志。

2. 中断处理函数
  • 典型结构

    
    static irqreturn_t my_interrupt_handler(int irq, void *dev_id) {struct my_device *dev = (struct my_device *)dev_id;// 处理中断逻辑return IRQ_HANDLED;
    }

  • 共享中断:需通过dev_id区分不同设备。

3. 驱动卸载(Remove函数)
  1. 禁用中断:调用disable_irq确保中断不再触发。

  2. 释放中断:通过free_irq解除注册。

  3. 清理资源:释放与dev_id关联的内存。


三、注意事项与最佳实践

1. 内存与资源管理
  • 使用devm_request_irq:自动管理资源,避免free_irq遗漏。

    
    int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev_id);

  • 错误处理:检查request_irqplatform_get_irq的返回值。

2. 共享中断处理
  • 标志设置:必须使用IRQF_SHARED

  • 唯一dev_id:每个设备需提供唯一的标识符(如设备结构体指针)。

3. 中断禁用与同步
  • 避免长时间禁用:可能导致中断丢失或系统延迟。

  • 自旋锁保护:在中断处理函数中使用自旋锁(spin_lock)保护共享数据。


四、完整示例代码

平台设备驱动示例

#include <linux/interrupt.h>
#include <linux/platform_device.h>struct my_device {struct device *dev;int irq;
};static irqreturn_t my_interrupt_handler(int irq, void *dev_id) {struct my_device *dev = dev_id;// 处理中断return IRQ_HANDLED;
}static int my_probe(struct platform_device *pdev) {struct my_device *dev;int irq, ret;dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);if (!dev) return -ENOMEM;irq = platform_get_irq(pdev, 0);if (irq < 0) return irq;ret = devm_request_irq(&pdev->dev, irq, my_interrupt_handler,IRQF_SHARED, "my_device", dev);if (ret) return ret;dev->irq = irq;platform_set_drvdata(pdev, dev);return 0;
}static int my_remove(struct platform_device *pdev) {struct my_device *dev = platform_get_drvdata(pdev);disable_irq(dev->irq);// free_irq 由 devm_request_irq 自动处理return 0;
}

五、常见问题解答

1. 为何free_irq需要dev_id参数?
  • 唯一标识:确保释放正确的中断处理程序,尤其在共享中断时。

2. disable_irqdisable_irq_nosync的区别?
  • 同步性disable_irq等待当前中断处理完成;disable_irq_nosync立即禁用。

3. 多次调用disable_irq的影响?
  • 计数机制:内核维护禁用计数,需相同次数的enable_irq重新启用中断。


通过合理使用上述函数,开发者能够高效管理中断资源,确保驱动程序的稳定性和响应能力。实际开发中需结合具体硬件和内核版本调整实现细节。

http://www.xdnf.cn/news/452.html

相关文章:

  • 国产的 Java Solon v3.2.0 发布(央企信创的优选)
  • Day10【基于encoder- decoder架构实现新闻文本摘要的提取】
  • 第3章 垃圾收集器与内存分配策略《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》
  • 从0开发一个unibest+vue3项目,使用vscode编辑器开发,总结vue2升vue3项目开始,小白前期遇到的问题
  • Flask应用部署通用指南
  • [Windows] Wireshark 网络抓包工具 v4.4.6
  • 【MATLAB海洋专题】历史汇总
  • C++学习之路,从0到精通的征途:vector类的模拟实现
  • 算法期末复习
  • 基于Fabric.js的选座布局系统开发笔记
  • 如何系统地入门学习stm32?
  • Linux419 三次握手四次挥手抓包 wireshark
  • python程序的流程
  • 移动自动化测试-appium
  • thanos rule组件和prometheus区别?
  • 5G基站设计难题:尺寸、重量、功耗和散热
  • HashMap 初步理解 put 操作流程 HashMap 的线程安全问题
  • 精益数据分析(5/126):解锁创业成功的关键密码
  • FPGA练习———DDS波形发生器
  • 一个项目中多个Composer的使用方法
  • 读文献方法
  • Linux系统之diff3命令详解
  • Nodejs数据库单一连接模式和连接池模式的概述及写法
  • 2024-04-19| Java: Documented注解学习 JavaDoc
  • 【网络篇】TCP vs UDP底层区别+网络编程概念
  • 网络爬虫和前端相关知识
  • 根据Exif信息纠正图片方向
  • MYSQL初阶(暂为自用草稿)
  • 哔哩哔哩工具箱:BiliTools v1.3.2
  • PyTorch数据操作基础教程:从张量创建到高级运算