linux kernel irq相关函数详解

发布于:2025-04-20 ⋅ 阅读:(78) ⋅ 点赞:(0)

在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重新启用中断。


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


网站公告

今日签到

点亮在社区的每一天
去签到