当前位置: 首页 > 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.lryc.cn/news/620815.html

相关文章:

  • Docker 入门与实战:从环境搭建到项目部署
  • Windows批处理脚本自动合并当前目录下由You-get下载的未合并的音视频文件
  • 【Unity3D实例-功能-移动】角色行走和奔跑的相互切换
  • AI智能体|扣子(Coze)搭建【批量识别发票并录入飞书】Agent
  • Cookie、Session、Token详解
  • 如何在 Ubuntu 24.04 LTS Noble Linux 上安装 Wine HQ
  • OpenCV对椒盐处理后的视频进行均值滤波处理
  • 短剧小程序系统开发:赋能创作者,推动短剧艺术创新发展
  • 【软件测试】自动化测试 — selenium快速上手
  • BitDock——让你的Windows桌面变为Mac
  • 如何查看SQL Server的当前端口
  • filezilla mac新版本MacOS-12.6.3会自动进入全屏模式BUG解决方法
  • 我的第一个开源项目-jenkins集成k8s项目
  • 软件测试中,常用的抓包工具有哪些?抓包的原理是什么?
  • FPGA读取AHT20温湿度模块思路及实现,包含遇到的问题(IIC协议)
  • 快速部署一个鉴黄服务
  • React数据请求
  • Android 项目:画图白板APP开发(二)——历史点、数学方式推导点
  • 2.0t的涡轮增压器结构设计说明书cad【5张】设计说明说
  • OpenSatKit技术详解
  • 《Leetcode》-面试题-hot100-动态规划
  • C++实现序列匹配与分类处理
  • 深度学习-卷积神经网络CNN-批量归一化 BatchNorm
  • React和Vue
  • React 中播放HLS 视频流 ,超简单的组件高度复用
  • 2019 GPT2原文 Language Models are Unsupervised Multitask Learners - Reading Notes
  • 微美全息(WIMI.US)借区块链与聚类技术,开启物联网去中心化安全架构新纪元
  • C#WPF实战出真汁03--登录功能实现
  • 阿里云Spring Cloud架构分析
  • 无人机双目视觉设计要点概述!