Linux内核中断(内核中断实现过程、注册三个按键中断实例、中断底半部实例、工作队列)

news2024/12/29 2:09:25

一、linux内核中断

1.目的:

用于对设备不用进行轮询访问,而是当设备事件发生后主动通知内核,内核再去访问设备。

2.linux内核中断实现过程框图

3.中断子系统API

1.解析中断相关的设备树节点

        struct device_node *of_find_compatible_node( struct device_node *from, const char *type, const char *compat)

2.解析设备中断的软中断号

        #include<linux/of_irq.h>

        unsigned int irq_of_parse_and_map(struct device_node *node, int index)

3.将中断注册进内核

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

4.注销中断

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

二、中断底半部

1.概念

        将一个中断处理得分过程分为了中断顶半部中断底半部,中断顶半部就是通过 request_irq注册的中断处理函数,在顶半部中主要进行一些重要的、不耗时的任务;中断底半部则是区进行一些耗时,不紧急的任务。在执行中断底半部时,会将执行中断顶半部时关闭的中断线启用以及抢占开启,这样进程以及其他的中断就可以正常的工作了。

2.实现机制

        softirq(软中断)、tasklet以及工作队列

3.API

1)分配一个tasklet对象

        struct tasklet_struct tasklet;

2)   初始化taklet对象

        void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)

        功能:当底半部处理函数是func类型时用此函数初始化对象

        void tasklet_setup(struct tasklet_struct *t, void (*callback)(struct tasklet_struct *))

        功能:当底半部处理函数是callback类型时用此函数初始化对象

3)开启底半部

        void tasklet_schedule(struct tasklet_struct *t)

三、工作队列

1.概述

工作队列用于底半部原理:内核中存在工作队列对应的内核线程,这个线程从内核启动就存在,处于休眠态。当有任务需要执行时,只需要将任务提交到工作队列中,然后唤醒休眠的内核线程,由内核线程去处理对应的任务即可。工作队列既可以用于中断,也可以用于进程

2.API

1)分配工作队列项

        struct work_struct work;

2)初始化队列项

        INIT_WORK(&work,底半部函数指针);

3)开启底半部

        bool schedule_work(struct work_struct *work)

注册三个按键中断实例

mykey_irq.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
/*   myirq{
       compatible="hqyj,myirq";
       interrupt-parent=<&gpiof>; 
       interrupts=<9 0>,<7 0>,<8 0>;  
   };*/
unsigned int irqno[3];
struct device_node *dnode;
//定义中断处理函数 
irqreturn_t key_handler(int irq, void *dev)
{
    int which=(int)dev;
    switch(which)
    {
        case 0:
            printk("KEY1_INTERRUPT\n");
            break;
        case 1:
            printk("KEY2_INTERRUPT\n");
            break;
        case 2:
            printk("KEY3_INTERRUPT\n");
            break;
    }
    return IRQ_HANDLED;
}

static int __init mycdev_init(void)
{
    //解析按键的设备树节点
    dnode=of_find_compatible_node(NULL,NULL,"hqyj,myirq");
    if(dnode==NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析设备树节点成功\n");
    //解析按键的软中断号
    int i;
    for(i=0;i<3;i++)
    {
    irqno[i]=irq_of_parse_and_map(dnode,i);
    if(!irqno[i])
    {
        printk("解析按键1软中断号失败\n");
        return -ENXIO;
    }
    printk("解析按键软中断号成功%d\n",irqno[i]);
    //注册 按键中断
    int ret=request_irq(irqno[i],key_handler,IRQF_TRIGGER_FALLING,"key_int",(void *)i);
    if(ret<0)
    {
        printk("注册按键中断失败\n");
        return ret;
    }
    
    }
    printk("注册按键中断成功\n");
    return 0;
}
static void __exit mycdev_exit(void)
{
    //注销中断
    int i;
    for(i=0;i<3;i++)
    {
    free_irq(irqno[i],(void *)i);
    }

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

测试现象:

中断底半部实例

mykey_tasklet.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
/*   myirq{
       compatible="hqyj,myirq";
       interrupt-parent=<&gpiof>; 
       interrupts=<9 0>,<7 0>,<8 0>;  
   };*/
unsigned int irqno[3];
struct device_node *dnode;
struct tasklet_struct tasklet;//分配对象
//定义底半部处理函数
void key_callback(struct tasklet_struct *t)
{
    int i;
    for(i=0;i<100;i++)
    {
        printk("i=%d\n",i);
    }
}
//定义中断处理函数 
irqreturn_t key_handler(int irq, void *dev)
{
    int which=(int)dev;
    switch(which)
    {
        case 0:
            printk("KEY1_INTERRUPT\n");
            break;
        case 1:
            printk("KEY2_INTERRUPT\n");
            break;
        case 2:
            printk("KEY3_INTERRUPT\n");
            break;
    }
    //开启底半部
    tasklet_schedule(&tasklet);
    return IRQ_HANDLED;
}

static int __init mycdev_init(void)
{
    //解析按键的设备树节点
    dnode=of_find_compatible_node(NULL,NULL,"hqyj,myirq");
    if(dnode==NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析设备树节点成功\n");
    //解析按键的软中断号
    int i;
    for(i=0;i<3;i++)
    {
    irqno[i]=irq_of_parse_and_map(dnode,i);
    if(!irqno[i])
    {
        printk("解析按键1软中断号失败\n");
        return -ENXIO;
    }
    printk("解析按键软中断号成功%d\n",irqno[i]);
    //注册 按键中断
    int ret=request_irq(irqno[i],key_handler,IRQF_TRIGGER_FALLING,"key_int",(void *)i);
    if(ret<0)
    {
        printk("注册按键中断失败\n");
        return ret;
    }
    
    }
    printk("注册按键中断成功\n");
    //初始化底半部
    tasklet_setup(&tasklet,key_callback);
    return 0;
}
static void __exit mycdev_exit(void)
{
    //注销中断
    int i;
    for(i=0;i<3;i++)
    {
    free_irq(irqno[i],(void *)i);
    }

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

【笔试强训选择题】Day44.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff…

CSS 滚动驱动动画 scroll-timeline ( scroll-timeline-name ❤️ scroll-timeline-axis )

scroll-timelinescroll-timeline-name❤️scroll-timeline-axis 解决问题语法 animation-timeline-nameanimation-timeline-axis scroll-timeline ( scroll-timeline-name ❤️ scroll-timeline-axis ) 在 scroll() 的最后我们遇到了因为定位问题导致滚动效果失效的情况, 当…

选择渲染农场的几个标准

随着电影、电视剧等影视作品的制作越来越依赖于计算机特效&#xff0c;渲染农场的使用也变得越来越普遍。渲染农场是一种利用大量计算机图形处理器&#xff08;GPU&#xff09;来加速渲染过程的服务。在选择渲染农场时&#xff0c;有几个标准可以帮助您确定哪个农场是适合您的项…

图神经网络系列之消息传递

文章目录 1.前言2.消息传递机制1.RecGNN2.ConvGNNs3.GAT 1.前言 相比较于神经网络最基本的网络结构全连接层&#xff08;MLP&#xff09;&#xff0c;特征矩阵乘以权重矩阵&#xff0c;图神经网络多了一个邻接矩阵。计算形式很简单&#xff0c;三个矩阵相乘再加上一个非线性变…

rv1126-rv1109-编译的剖析

./build.sh uboot:cmds./build.sh ubootcd u-boot make rv1126_defconfig make menuconfig ### 保存配置到对应的⽂件rv1126_defconfig make savedefconfig cp defconfig configs/rv1126_defconfig //剖析 ./build.sh uboot //调用 ./mk-loader.sh build.sh -> mk-all.sh …

软件安全测试为什么重要?安全测试应该怎么进行?

在当前数字化时代&#xff0c;软件已经成为我们生活中不可或缺的一部分&#xff0c;无论是在工作中还是生活中&#xff0c;我们都离不开各种各样的软件。然而&#xff0c;随着软件的普及和应用范围的扩大&#xff0c;软件安全问题也逐渐凸显出来&#xff0c;给企业和个人带来了…

无涯教程-JavaScript - SECH函数

描述 SECH函数返回某个Angular的双曲正割。双曲正割是双曲余弦的倒数。因此,双曲正割的值由等式给出- $$\sinh\left(x\right)\frac {1} {\cosh\left(x\right)} \frac {2} {e ^ x e ^ {-x}} $$ 语法 SECH (number)争论 Argument描述Required/OptionalNumberNumber is the …

Backup: MML shutdown 忽略

RMAN Backup Job is Completed But RMAN Sessions are Not Released in Database When Using Netbackup (Doc ID 2903139.1)​编辑To Bottom In this Document Symptoms Changes Cause Solution APPLIES TO: Oracle Database - Enterprise Edition - Version 19.8.0.0.0 and …

Outlook打开超链接用默认浏览器Microsoft outlook open hyperlink using default browser

这两天outlook打开超链接一直用edge&#xff0c;但我的默认浏览器是chrome。 解决方法 在outlook的选项中的高级设置里面&#xff0c;将超链接打开选为默认浏览器。

「UG/NX」Block UI 指定位置SpecifyLocation

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

Navicat中查询指定字段名所在的表名

Navicat中查询指定字段名所在的表名 代码如下&#xff1a; SELECT * FROM information_schema.COLUMNS WHERE COLUMN_NAME替换成你要查找的字段;显示结果如下&#xff1a; 或者这段代码&#xff1a; SELECT table_name, column_name FROM information_schema.columns WHERE c…

二刷力扣--二叉树(1)基础、遍历

二叉树基础 常见的二叉树。 两类特殊的二叉树&#xff0c;满二叉树和完全二叉树。 满二叉树即一棵节点满了的二叉树&#xff0c;想要再添加一个节点只能添加一层了。 完全二叉树:照着满二叉树从上到下&#xff0c;从左到右的顺序添加节点&#xff0c;中间的过程都是完全二叉…

安装VS2015时提示安装包丢失或损坏

今天安装VS2015社区版本时&#xff0c;提示缺失以下两个内容&#xff1a; Microsoft VisualStudio JavaScript Project System : 找不到元素。 Microsoft VisualStudio JavaScript Language Service : 系统找不到指定的文件。 虽然似乎不影响C代码的运行&#xff0c;但是我怕有…

数据结构_复杂度讲解(附带例题详解)

文章目录 前言什么是数据结构&#xff1f;什么是算法&#xff1f;一. 算法的时间复杂度和空间复杂度1.1 算法效率1.2 如何衡量一个算法好坏 二. 时间复杂度2.1 时间复杂度概念例题一例题一分析 实例一实例一分析 三. 空间复杂度实例实例问题解析 四. 常见复杂度对比五. 常见时间…

Linux查找文件内容的命令

在Linux中&#xff0c;您可以使用以下命令来查找文件内容&#xff1a; grep命令&#xff1a; grep命令用于在文件中搜索指定的文本模式&#xff0c;并将包含匹配的行打印出来。语法如下&#xff1a; grep "要查找的文本" 文件名例如&#xff0c;要在名为example.txt的…

激光雷达录制pcap类型的包

查看IP 上图中的eno1就是网卡名&#xff0c;就可以使用如下命令录制 sudo tcpdump -i eno1 host 192.168.1.200 -w lidar.pcap-i 后面是网卡名&#xff0c;host 后面是ip&#xff0c;-w后是pcap包名称。

在Spring Boot API Gateway中实现Sticky Session

文章目录 小结问题在API Gateway中实现Sticky Session在同一个API Gateway中同时支持Sticky Session和RoundRobinLoadBalancer参考 小结 在Kubernetes微服务的云环境中&#xff0c;如何在Spring Boot API Gateway中实现Sticky Session&#xff0c;当服务请求被某一个服务器处理…

晶码存档&改造【01】模板导入租户登录

app101改造之前 想搞一个设备导入功能&#xff0c; 想象中 实际上 再改改样式 关于数据的导入导出&#xff1a; 可见博客 APEX数据源加载实现Excel表数据导入及自定义存储过程_王小小鸭的博客-CSDN博客https://blog.csdn.net/clover_oreo/article/details/132575970?csdn_s…

华为HCIA(五)

Vlan id 在802.1Q中 高级ACL不能匹配用户名和源MAC 2.4G频段被分为14个交叠的&#xff0c;错列的20MHz信道&#xff0c;信道编码从1到14&#xff0c;邻近的信道之间存在一定的重叠范围 STA通过Probe获取SSID信息 Snmp报文 网络管理设备异常发生时会发送trap报文 D类地址是…

【git】超详细使用指令

git指令 暂存区工作区提交到暂存区暂存区覆盖到工作区暂存区移除文件暂存区提交到版本库 git储藏场景条件 版本库版本库回退 忽略文件新建.gitignore文件&#xff0c;填入相应配置忽略文件 分支创建分支命令切换分支命令查看所有分支 分支合并切回要合入的分支上合并其他分支过…