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

imx6ull-驱动开发篇24——Linux 中断API函数

目录

Linux 中断 API 函数

中断号

request_irq 函数

函数参数

独占中断(非共享)​

共享中断​

free_irq 函数

中断处理函数

函数格式

示例代码

中断使能与禁止函数

函数介绍

示例代码


在裸机实验里面中断的处理方法:GPIO中断实验

  • 使能中断,初始化相应的寄存器。
  • 注册中断服务函数,也就是向 irqTable 数组的指定标号处写入中断服务函数。
  • 中断发生以后进入 IRQ 中断服务函数,在 IRQ 中断服务函数在数组 irqTable 里面查找具体的中断处理函数,找到以后执行相应的中断处理函数。

那么,linux下又是如何使用中断的呢?让我们一起学习一下linux中断的API函数吧~

Linux 中断 API 函数

中断号

每个中断都有一个中断号,通过中断号即可区分不同的中断,有的资料也把中断号叫做中断线。

在 Linux 内核中使用一个 int 变量表示中断号:

中断号范围​​:

  • 传统 IRQ:0~15(x86 PIC),0~NR_IRQS(现代系统可能扩展至数千)。

  • 虚拟中断(如 MSI-X):动态分配,可能远超物理 IRQ 数量。

request_irq 函数

在 Linux 内核中,使用request_irq 函数用于申请中断, request_irq函数可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用 request_irq 函数。

函数参数

request_irq 函数会激活(使能)中断,函数原型如下:

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

其中,flags:中断标志,可以在文件 include/linux/interrupt.h 里面查看所有的中断标志。常见的中断标志如下:

request_irq函数的返回值: 0 中断申请成功,其他负值:中断申请失败,如果返回-EBUSY 的话表示中断已经被申请了。

示例代码:

独占中断(非共享)​

irqreturn_t my_handler(int irq, void *dev_id) {printk("Interrupt %d handled by device %s\n", irq, (char *)dev_id);return IRQ_HANDLED;
}int setup_irq(void) {int irq_num = 5; // 假设硬件中断号为 5char *dev_name = "my_device";if (request_irq(irq_num, my_handler, IRQF_TRIGGER_RISING, dev_name, NULL)) {printk("Failed to register IRQ %d\n", irq_num);return -EIO;}return 0;
}

共享中断​

struct my_device {char *name;int data;
};irqreturn_t shared_handler(int irq, void *dev_id) {struct my_device *dev = dev_id;printk("IRQ %d by %s (data=%d)\n", irq, dev->name, dev->data);return IRQ_HANDLED;
}int setup_shared_irq(void) {struct my_device dev1 = { .name = "dev1", .data = 42 };int irq_num = 16;if (request_irq(irq_num, shared_handler, IRQF_SHARED | IRQF_TRIGGER_HIGH, "shared_irq", &dev1)) {printk("Failed to register shared IRQ\n");return -EIO;}return 0;
}

free_irq 函数

通过 request_irq 函数申请中断,通过 free_irq 函数释放掉相应的中断。如果中断不是共享的,那么 free_irq 会删除中断处理函数并且禁止中断。

free_irq函数原型如下所示:

void free_irq(unsigned int irq,  void *dev)

示例代码如下:

//1.  释放独占中断
void cleanup_irq(void) {int irq_num = 5; // 假设之前注册的中断号为 5free_irq(irq_num, NULL); // 非共享中断时 dev 可为 NULL
}// 2.  释放共享中断​
struct my_device {char *name;int data;
};void cleanup_shared_irq(void) {static struct my_device dev1 = { .name = "dev1", .data = 42 };int irq_num = 16;free_irq(irq_num, &dev1); // 必须传递与注册时相同的 dev 指针
}

中断处理函数

使用 request_irq 函数申请中断的时候需要设置中断处理函数。

函数格式

中断处理函数格式如下所示:

irqreturn_t (*irq_handler_t) (int, void *)

中断处理函数的返回值为 irqreturn_t 类型, irqreturn_t 类型定义如下所示:

enum irqreturn {IRQ_NONE        = (0 << 0),IRQ_HANDLED     = (1 << 0),IRQ_WAKE_THREAD = (1 << 1),
};
typedef enum irqreturn irqreturn_t;

可以看出 irqreturn_t 是个枚举类型,一共有三种返回值。

示例代码

// 1. ​​基础中断处理​irqreturn_t my_interrupt_handler(int irq_num, void *dev_id) {struct my_device *dev = dev_id;if (!check_device_irq(dev))  // 检查是否为本设备中断return IRQ_NONE;         // 非本设备中断,不处理process_hardware_irq(dev);   // 处理中断return IRQ_HANDLED;          // 确认已处理
}// 2. 共享中断处理​
irqreturn_t shared_handler(int irq_num, void *dev_id) {struct my_device *dev = dev_id;if (read_device_status(dev) != IRQ_TRIGGERED)return IRQ_NONE;  // 非本设备中断handle_irq_logic(dev);return IRQ_HANDLED;
}// 注册共享中断
request_irq(irq_num, shared_handler, IRQF_SHARED, "shared_irq", &device1);
request_irq(irq_num, shared_handler, IRQF_SHARED, "shared_irq", &device2);// 3.  线程化中断
irqreturn_t threaded_handler(int irq_num, void *dev_id) {// 快速处理硬件操作(在硬中断上下文中)return IRQ_WAKE_THREAD;  // 唤醒关联线程
}static irqreturn_t threaded_part(int irq_num, void *dev_id) {// 耗时的处理(在进程上下文中)return IRQ_HANDLED;
}// 注册线程化中断
request_threaded_irq(irq_num, threaded_handler, threaded_part, IRQF_ONESHOT, "threaded_irq", NULL);

中断使能与禁止函数

函数介绍

常用的中断使用和禁止函数如下所示:

void enable_irq(unsigned int irq);  // 启用中断
void disable_irq(unsigned int irq); // 禁用中断

enable_irq 和 disable_irq 用于使能和禁止指定的中断, irq 就是要禁止的中断号。

disable_irq函数要等到当前正在执行的中断处理函数执行完才返回,因此使用者需要保证不会产生新的中断,并且确保所有已经开始执行的中断处理程序已经全部退出。

还有一个中断禁止函数:

void disable_irq_nosync(unsigned int irq)

disable_irq_nosync 函数调用以后立即返回,不会等待当前中断处理程序执行完毕。

使能和禁止全局中断函数如下:

local_irq_enable()
local_irq_disable()
local_irq_save(flags)
local_irq_restore(flags)

示例代码

// 1.  保护短临界区(如自旋锁)
spinlock_t lock;
unsigned long flags;local_irq_save(flags);   // 禁用中断并保存状态
spin_lock(&lock);        // 获取自旋锁
// 操作共享数据...
spin_unlock(&lock);      // 释放锁
local_irq_restore(flags); // 恢复中断状态// 2.  中断上下文中的原子操作
irqreturn_t irq_handler(int irq, void *dev_id) {unsigned long flags;local_irq_save(flags);  // 防止中断嵌套// 修改硬件寄存器或全局变量local_irq_restore(flags);return IRQ_HANDLED;
}// 3.  内核定时器回调​
void timer_callback(struct timer_list *t) {unsigned long flags;local_irq_save(flags);// 处理时间敏感任务(避免被中断打断)local_irq_restore(flags);
}
http://www.dtcms.com/a/331066.html

相关文章:

  • MATLAB绘制各种心形曲线
  • window显示驱动开发—在混合系统中使用跨适配器资源
  • nginx-集成prometheus监控(k8s)
  • GitHub 热榜项目 - 日榜(2025-08-14)
  • 一、linux内存管理学习(1):物理内存探测
  • 京东商品列表API开发指南
  • OpenCV对椒盐处理后的视频进行均值滤波处理
  • Opencv 边界填充 图像运算 阈值处理 和图像平滑处理
  • 文件上传接口接收不到文件入参
  • 题解:P4777 【模板】扩展中国剩余定理(EXCRT)
  • Qt项目查找依赖库打包
  • IDEA、Pycharm、DataGrip等激活破解冲突问题解决方案之一
  • Springboot项目重启后Session依旧存在
  • Python包性能优化与并发编程:构建高性能应用的核心技术(续)
  • 轻量级开源全文搜索引擎:Manticore Search 入门介绍
  • C++基础(①入门教程)
  • 本地jar导入到本地仓科和远程仓库
  • Maven学习笔记
  • 92、23种设计模式-单例模式
  • 项目日志框架与jar中日志框架冲突 解决
  • 《多级缓存架构设计与实现全解析》
  • 自动化测试|持续集成Git使用详解
  • label studio 服务器端打开+xshell端口转发设置
  • 01数据结构-最短路径Dijkstra
  • 【数据结构入门】
  • 移动机器人底盘在高校科研中的AI智能教育应用
  • (第十五期)HTML文本格式化标签详解:让文字更有表现力
  • Flutter GetX 全面指南:状态管理、路由与依赖注入的最佳实践
  • SpringMVC请求与响应
  • 三坐标测量仪:从机械精密到智能协同的技术