Linux驱动学习之中断与等待队列

news2024/12/31 4:24:30

本篇分为设备树部分和API接口部分

设备树

想要使用中断,设备树中需要有两个属性:

interrupts                   // 表示要使用哪一个中断, 中断的触发类型等等。

interrupt-parent         // 这个中断要接到哪一个设备去? 即父中断控制器是谁

父中断控制器有两种指定方法:

  • 只有一个父中断设备
  • 有多个父中断设备

1)、只有一个父中断设备

interrupt-parent = <&父设备标号>;

 interrupts = <... ...>, <... ...>;

2)、有多个父设备节点

interrupts-extended = <&父设备标号 .....>, <... ... ...>;

通过不断往里跳可以发现 设备树查找有这两种方式

方法一

此方法中,由于查看父节点是靠 interrupt-parent实现的,所以此属性不可少. 

方法二 

不断跳就会发现这个循环

此方法中是通过属性中第一个元素找出的父节点,所以无需指定中断父节点 

上述属性用多少个u32表示

由它的父中断控制器来描述,在父中断控制器中, 至少有2个属性:

interrupt-controller; // 表示自己是一个中断控制器

#interrupt-cells // 表示自己的子设备里应该用几个U32的数据来描述中断

如此图,此节点是父节点中断控制器,他的子节点用2个u32 描述中断。

如何找到一个节点的父中断控制器

一般在描述子中断节点中都会有一个属性interrupt-parent,由此属性描述。

如果子中断节点中没有此属性,需要查看此节点的父节点,一级一级往上直到父节点中出现interrupt-parent。

API函数

获取中断号

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

参数一:平台设备,

参数二:设备树里第几个中断引脚,一般给0

返回值:中断号

ps:需要在设备树里指定。

int gpio_to_irq(unsigned gpio)

参数:io口号

返回值:中断号

ps:此函数无需在设备树里指定中断信息,直接调用可直接在根目录下的gpio中断控制器里申请返回一个中断号,一旦在设备树里指定,也可获得中断号,不过与不指定的中断号可能存在差异,不过不影响,都可以实现中断。

注册中断 

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

参数一:中断号

参数二:中断回调函数

参数三:在什么边沿触发

参数四:标签,可随意

参数五:中断回调函数传入的参数

int 
devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
		 unsigned long irqflags, const char *devname, void *dev_id)

此函数也可以注册中断,建议使用这个,参数跟上面函数大差不差不在重复介绍。

devm_request_irq和request_irq区别在于前者是申请的内核“managed”资源,不需要自己手动释放,会自动回收资源,而后者需要手动调用free_irq来释放中断资源 

中断回调函数类型

flag类型

注销函数

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

参数一:中断号

参数二:与注册函数传入参数一致。

void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id)

 参数与上述函数一致,注意配套使用

使用中断后,我们就可以在按下按键后就可以收到一次消息,但是由于上层函数在while循环里一直执行,每调用一次read就会调用底层内核的read,不会阻塞,所以cpu占用率百分之百,此时这就是个病毒驱动。但是我们在学习系统编程的时候,read是一个阻塞函数,当然那时内核实现的他的阻塞,所以我们就需要在内核里把read阻塞,当按键按下进入中断再让read解除阻塞,减少cpu的占用率。

等待队列

等待队列是目前内核最常用的阻塞同步机制之一
        可以在内核层产生一个阻塞( 等于放弃 CPU 的! )
        while(1); ->这种叫死等 -> 效率最低 占用 CPU 最高一种等待机制
        所有的系统的等待机制都绝非死等-> 都是放弃 CPU ,后续被换唤醒机制!
        在 FreeRTOS 大家应该接触过类似的概念
等待队列非常类似之前大家在系统层面学习 线程的同步和互斥:条件变量!
        等待队列除了创建之外就两个函数,也是两个功能:
                一个功能叫做: 阻塞 -> 调用后立刻产生挂起
                wait_event
                唤醒->调用会唤醒之前挂起进程 / 程序
                wake_up
  内核层的阻塞会引起上层的阻塞!
        举个例子:我在 open-> 调用 阻塞 ” -> 上层 open 也会阻塞
                我在 read->调用 阻塞 ” –> 上层 read 也会阻塞

 等待队列的创建:(宏定义函数->用空间换时间)

DECLARE_WAIT_QUEUE_HEAD(name);
#define DECLARE_WAIT_QUEUE_HEAD(name)                                          \
    struct wait_queue_head name = __WAIT_QUEUE_HEAD_INITIALIZER(name)

// Expands to
struct wait_queue_head queue = { . lock = ( spinlock_t ) { { . rlock = { . raw_lock = { { . val = { ( 0 ) } } } , } } } , . head = { & ( queue ) . head , & ( queue ) . head } }

此函数为宏函数, 声明的时候已经帮我们初始化好了,括号里面是我们创建的变量名字

阻塞函数 

 wait_event_interruptible(wq_head, condition)

此函数也也为宏函数,可以看出,当condition为1时,不阻塞,为0时阻塞,另外第二个参数必须为变量,如果填0,则当唤醒函数执行后不会解除阻塞。wait_event_interruptible(以及wait_event打头的其他变体)是Linux的wait queue机制提供的线程同步接口(应先cond=0,把cond传进去)另外也可以看出,参数一直接传入变量名即可

唤醒函数

wake_up_interruptible(x)

此函数也为宏函数, 跳进去可发现,参数传入变量名地址。调用完该函数cond设置为1.

整体代码

#include "linux/cdev.h"
#include "linux/device.h"
#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/interrupt.h"
#include "linux/irq.h"
#include "linux/module.h"
#include "linux/of_device.h"
#include "linux/of_gpio.h"
#include "linux/platform_device.h"
#include "linux/printk.h"
#include "linux/types.h"
#include "linux/uaccess.h"
#include "linux/wait.h"
#include "linux/zconf.h"
uint32_t pin;
dev_t dev_num;
struct cdev *cdev;
struct class *cls;
struct device * dev;
uint8_t cond;
DECLARE_WAIT_QUEUE_HEAD(queue);
uint8_t val;
irqreturn_t fun(int i, void * a)
{
    val=gpio_get_value(pin);
   printk("%d\r\n",val);
    wake_up_interruptible(&queue);
    cond=1;
    return 0;
}
static ssize_t read(struct file *f, char __user *b, size_t s, loff_t *offt)
{
    cond=0;
    wait_event_interruptible(queue,cond);
    int a=copy_to_user(b,&val,1);
    if(a)
    {
        
    }
    return 0;
}
static int open(struct inode *i, struct file *f)
{
    int ret=devm_request_irq(dev, gpio_to_irq(pin),fun,IRQ_TYPE_EDGE_FALLING,"key", NULL);
   printk("%d\r\n",ret);
    return ret;
}
static int close(struct inode *i, struct file *f)
{
  devm_free_irq(dev,gpio_to_irq(pin),NULL);
    return 0;
}
struct file_operations fops={
   .owner=THIS_MODULE,
   .read=read,
   .open=open,
   .release=close,
};

int probe(struct platform_device *d)
{
    // DECLARE_WAIT_QUEUE_HEAD(name);
    // wait_event_interruptible(,);
    // wake_up_interruptible(x)
    
    platform_get_irq();
   //free_irq();
   // devm_free_irq();
   dev=&d->dev;
    pin=of_get_named_gpio(d->dev.of_node,"key_pin",0);
   
    printk("%d\r\n",pin);
   printk("%d\r\n", platform_get_irq(d,0));
    printk("irq_num=%d", gpio_to_irq(pin));
    gpio_request(pin,"key");
    gpio_direction_input(pin);
   // devm_request_irq(&d->dev, gpio_to_irq(pin),fun,IRQ_TYPE_EDGE_FALLING,"key", NULL);
    alloc_chrdev_region(&dev_num, 0, 1,"key");
    cdev=cdev_alloc();
    cdev->ops=&fops;
    cdev_add(cdev,dev_num,1);
    cls=class_create(THIS_MODULE, "key");
    device_create(cls, NULL,dev_num,NULL,"key");
    return 0;
}
int remove(struct platform_device *d)
{
    return 0;
}
static struct of_device_id match={
    .compatible="key",
};

static struct platform_driver driver={
    .probe=probe,
    .remove=remove,
    .driver={
        .name="key",
        .of_match_table=&match,
    },
};
static int __init start(void)
{
    platform_driver_register(&driver);
    printk(KERN_INFO "Hello, world!\n");
    return 0;
}
static void __exit stop(void)
{
    platform_driver_unregister(&driver);
    printk(KERN_INFO "Goodbye, world!\n");
}
module_init(start);
module_exit(stop);
MODULE_LICENSE("GPL");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2076443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一种更快成像的新技术

斯旺西大学&#xff08;Swansea University&#xff09;的研究人员为中性原子束显微镜创造了一种新的成像方法&#xff0c;可大大加快显微镜图像的获取速度。中性原子束显微镜已成为科学研究的一个重点&#xff0c;因为它能够对商用显微镜无法成像的表面进行成像&#xff0c;例…

mysql集群从零开始搭建

文章目录 MySQL集群linux下部署mysqlmysql主从复制master配置配置slave新的slave加入延迟复制慢查询多线程原理 半同步模式原理gat模式启动半同步模式 mysql高可用之组复制&#xff08;MGR&#xff09;实现mysql组复制 mysql路由具体实现 mysql高可用之MHAMHA部署实施安装MHA软…

Codeforces Round 968 (Div. 2 ABCD1D2题) 视频讲解

A. Turtle and Good Strings Problem Statement Turtle thinks a string s s s is a good string if there exists a sequence of strings t 1 , t 2 , … , t k t_1, t_2, \ldots, t_k t1​,t2​,…,tk​ ( k k k is an arbitrary integer) such that: k ≥ 2 k \ge 2 k≥…

接口自动化测试利器,使用Rest Assured进行REST API测试

我们在做接口测试时&#xff0c;一般在代码中会使用HttpClient&#xff0c;但是HttpClient相对来讲还是比较麻烦的&#xff0c;代码量也相对较多&#xff0c;对于新手而言上手会比较难一点&#xff0c;今天我们来看下另一个接口测试工具包REST Assured REST Assured是一个流行…

Blazor官方文档学习记录

Blazor官方文档学习记录 1 官方文档2 Blazor教程-生成首个应用3 项目结构4 基础知识4.1 生态4.2 Razor组件指令顺序4.3 Razor组件的初始化方法 5 注意 1 官方文档 https://dotnet.microsoft.com/zh-cn/apps/aspnet/web-apps/blazor2 Blazor教程-生成首个应用 https://dotnet.…

Python | Linux | 解析Himawari-8/9 | Standard Data

写作前面 之前一个相关的工作需要解析Himawari-8/9 Standard Data文件&#xff0c;因为他是二进制的&#xff0c;之前没有处理过&#xff0c;导致完全摸不着头脑。在网上找了中英文搜索找了好久&#xff0c;虽然也找到了公开的解析代码&#xff0c;但是放在自己的数据这感觉总是…

趣味算法------猴子吃桃(循环,递归双重解法)

题目描述 猴子第一天摘下若干个桃子&#xff0c;当天吃了一半&#xff0c;后面又多吃一个。第二天早上又将剩下的桃子吃掉一半&#xff0c;又多吃了一个。后面每天猴子都吃了前一天剩下的一半零一个。到第十天想再吃时&#xff0c;只剩下一个桃子。求第一天共摘了多少桃子。 …

鸿蒙(API 12 Beta3版)【获取音视频元数据】音频播放与录制

使用AVMetadataExtractor可以实现从原始媒体资源中获取元数据&#xff0c;本开发指导将以获取一个音频资源的元数据作为示例&#xff0c;向开发者讲解AVMetadataExtractor元数据相关功能。视频资源的元数据获取流程与音频类似&#xff0c;由于视频没有专辑封面&#xff0c;所以…

【中仕公考怎么样】公务员备考小建议

2025年国考在即&#xff0c;掌握正确的备考方法很重要&#xff01;中仕为大家简单分享4点小技巧。 1. 在提升行测分数时&#xff0c;可以采用大量的练习题、整理题以及关注往年核心考点的方式。无论处于准备过程的哪一阶段&#xff0c;对各类题型进行深入分析并掌握相应的解题…

C++ | Leetcode C++题解之第373题查找和最小的K对数字

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {int m nums1.size();int n nums2.size();auto count [&](int target){long long …

怎么用AI生成PPT演讲稿?5个方法教你快速生成

想象一下&#xff0c;你正在准备一场关于“墨西哥是如何走到今天这一步的”演讲&#xff0c;而你却苦于如何将复杂的历史背景、经济变迁以及文化特色等内容有机地整合进一份PPT中。 这时候&#xff0c;一款好的AI自动生成PPT的工具就能派上用场了。它不仅能够帮助你快速构建起…

C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤

前言 嗨&#xff0c;各位码农们&#xff01;今天我们要来聊聊如何在 C# 的 WinForms 应用程序中用 MDI&#xff08;Multiple Document Interface&#xff09;模式来优雅地管理多个子窗体。 如果你曾经对着一堆乱七八糟的窗体不知所措&#xff0c;或者想要让你的应用程序看起来…

基于SpringBoot的线上教学平台系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言 Java 数据库 MySQL 技术 SpringBoot框架&#xff0c;Java语言 工具 IDEA/Eclipse、Navicat、Maven 系统展示 首页 管理员功能模块 学员功能模块 前台首页…

16行为型设计模式——策略模式

一、策略模式简介 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一系列的算法&#xff0c;将每一个算法封装起来&#xff0c;并使它们可以相互替换。具体的算法选择交由客户端决定&#xff0c;即不同的算法可以在运行时动态地&a…

后端微服务架构:构建分布式博客系统

后端微服务架构&#xff1a;构建分布式博客系统 在当今的软件开发领域&#xff0c;微服务架构已经成为构建可扩展、灵活且易于维护的应用程序的主流选择。本文将探讨如何利用微服务架构来设计和实现一个分布式的博客系统。 1. 微服务架构简介 微服务架构是一种将应用程序分解…

练习题 期望dp

题目 分析&#xff1a; 首先注意到期望有线性性&#xff1a; E ( a b ) E ( a ) E ( b ) E(ab)E(a)E(b) E(ab)E(a)E(b)&#xff0c;其中 a a a、 b b b不要求相互独立。 因为网上很多地方的证明不严谨&#xff0c;所以这里证明一下&#xff1a; E ( a b ) ∑ i i ⋅ P …

C语言基础(十八)

1、共用体&#xff08;Union&#xff09;是一种特殊的数据类型&#xff0c;也被称为联合体&#xff0c;它允许在相同的内存位置存储不同的数据类型&#xff0c;每次只能存储其中一种类型的值。共用体是一种数据结构&#xff0c;多个不同类型的变量能够共享同一段内存空间。在C语…

OpenAI推出新功能:GPT-4o正式上线微调功能,限时免费!

GPT-4o正式上线微调功能&#xff0c;限时免费&#xff01; 每个组织每天可以免费获得多达100万个训练token&#xff0c;活动将持续到9月23日。 这意味着开发者们现在可以利用自定义数据集对GPT-4o进行微调&#xff0c;从而以较低的成本构建自己的应用程序。 据悉&#xff0c;G…

推荐3款在Windows系统上运行流畅、音质出众的音乐播放器

foobar2000 Foobar2000是一款由原Winamp开发公司的Peter Pawlowski开发的免费多功能音频播放器&#xff0c;具有高度定制化和丰富的功能。它支持多种音频格式&#xff0c;包括MP3、AAC、WMA、FLAC、WAV等&#xff0c;并且可以进行音频转码和格式转换。此外&#xff0c;Foobar20…

C盘满了,如何清理C盘

目录 磁盘清理删除休眠文件查看系统盘的存储占比卸载掉安装在系统盘的软件更改临时文件、文档等的存储位置 磁盘清理 选择自己的系统盘&#xff0c;我的是G盘。清理系统文件删除休眠文件 删除休眠文件 管理员打开cmd powercfg -h off 直接减少几个g的C盘占用 查看系统盘的存储…