驱动作业,按键中断阻塞LED灯

 驱动程序

#include "head.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/seqlock.h>
#include <linux/atomic.h>
#include <linux/wait.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/poll.h>
#include <linux/time.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>char kbuf[128] = {0}; // 用来接用户空间传递的数据// 定义指针接收映射成功的虚拟内存首地址
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;// 接收struct class/struct device 类型空间的首地址
struct class *cls;
struct device *dev;struct cdev *cdev;      // 字符驱动设备空间地址
unsigned int major = 0; // 主设备号
unsigned int minor = 0; // 次设备号
dev_t devnum;           // 设备号unsigned int condition=0;   //定义有无数据判断值//定义等待队列头
wait_queue_head_t wq_head;// 设备节点指针
struct device_node *dnode;
// 中断号
unsigned int key_irqnum[3];
// gpio_desc对象指针
struct gpio_desc *desc[3];
unsigned number=0;// 定义中断处理函数
irqreturn_t key_handler(int irq, void *dev)
{number=!number;switch ((int)dev){case 0: // key1printk("key1 interrupt\n");gpiod_set_value(desc[0], !gpiod_get_value(desc[1]));break;case 1: //key2printk("key2 interrupt\n");gpiod_set_value(desc[1], !gpiod_get_value(desc[1]));break;case 2: //key3printk("key3 interrupt\n");gpiod_set_value(desc[2], !gpiod_get_value(desc[2]));break;}condition=1;wake_up_interruptible(&wq_head);return IRQ_HANDLED; // 中断正常处理
}// 封装操作方法,自己封装的函数
int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{int ret;//把进程切换为休眠态wait_event_interruptible(wq_head,condition);//把准备好的硬件数据拷贝到用户空间ret=copy_to_user(ubuf,&number,size);if(ret){printk("cpoy_to_user error\n");return ret;}condition=0;    //表示下次数据没有准备好printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{printk("%s:%s:%d:%s\n", __FILE__, __func__, __LINE__, kbuf);return 0;
}int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}// 定义操作方法结构体变量并初始化,让结构体变量指向自己封装的函数名
struct file_operations fops = {.open = mycdev_open,.read = mycdev_read,.write = mycdev_write,.release = mycdev_close,
};static int __init mycdev_init(void)
{int i; // 设备节点int ret;//初始化等待队列头init_waitqueue_head(&wq_head);// 1.分配字符设备驱动对象// 申请一个字符设备对象驱动空间cdev = cdev_alloc();if (cdev == NULL){printk("cdev_alloc error\n");ret = -EFAULT;goto OUT1;}printk("申请字符设备驱动成功\n");// 2.初始化字符设备驱动对象cdev_init(cdev, &fops);// 3.申请设备号if (major > 0) // 静态申请设备号{ret = register_chrdev_region(MKDEV(major, minor), 3, "mychrdev");if (ret){printk("静态申请设备号失败\n");goto OUT2;}printk("静态申请设备号成功\n");}else if (major == 0){ret = alloc_chrdev_region(&devnum, minor, 3, "mychrdev");if (ret){printk("动态申请设备号失败\n");goto OUT2;}printk("动态申请设备号成功\n");minor = MINOR(devnum); // 根据设备号获取次设备号major = MAJOR(devnum); // 根据设备号获取主设备号}// 4.注册字符设备驱动对象ret = cdev_add(cdev, MKDEV(major, minor), 3);if (ret){printk("注册字符设备驱动对象失败\n");goto OUT3;}printk("注册字符设备驱动对象成功\n");// 5.向上提交目录信息cls = class_create(THIS_MODULE, "mycdev");if (IS_ERR(cls)){printk("向上提交目录信息失败\n");ret = -PTR_ERR(cls);goto OUT4;}printk("向上提交目录信息成功\n");// 6.向上提交设备节点信息for (i = 0; i < 3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);if (IS_ERR(dev)){printk("向上提交设备节点信息失败\n");ret = -PTR_ERR(dev);goto OUT5;}}printk("向上提交设备节点信息成功\n");//-------------------------解析按键的设备树节点--------------------------dnode = of_find_compatible_node(NULL, NULL, "zmgh,myirq");if (dnode == NULL){printk("解析设备树节点失败\n");return -ENXIO;}printk("解析设备树节点成功\n");for (i = 0; i < 3; i++){// 根据按键的设备树节点解析按键1的软中断号key_irqnum[i] = irq_of_parse_and_map(dnode, i);if (!key_irqnum[i]){printk("解析按键1的软中断号失败\n");goto OUT6;}printk("解析按键1的软中断号成功  %d\n", key_irqnum[i]);// 注册中断,下降沿触发ret = request_irq(key_irqnum[i], key_handler, IRQF_TRIGGER_FALLING, "key", (void *)i);if (ret < 0){printk("注册中断失败\n");return -ENXIO;}}printk("注册中断成功\n");// ------------------------解析LED设备树节点,根据路径解析--------------------dnode = of_find_node_by_path("/leds");if (dnode == NULL){printk("解析设备树节点失败\n");return -ENXIO;}printk("解析设备树节点成功\n");// 申请gpio_desc对象并设置输出为低电平desc[0] = gpiod_get_from_of_node(dnode, "led-gpios", 0, GPIOD_OUT_LOW, NULL);desc[1] = gpiod_get_from_of_node(dnode, "led-gpios", 1, GPIOD_OUT_LOW, NULL);desc[2] = gpiod_get_from_of_node(dnode, "led-gpios", 2, GPIOD_OUT_LOW, NULL);for (i = 0; i < 3; i++){if (IS_ERR(desc[0])){printk("申请gpio对象失败\n");return -PTR_ERR(desc[i]);}}printk("申请gpio对象成功\n");return 0;
OUT6://注销软中断号for (--i; i >= 0; i--){// 注销中断free_irq(key_irqnum[i], NULL);}
OUT5:// 注销目录信息for (--i; i >= 0; i--){// 释放提交成功的设备节点信息device_destroy(cls, MKDEV(major, i));}class_destroy(cls); // 销毁目录
OUT4:// 注销字符设备驱动对象cdev_del(cdev);
OUT3:// 注销设备号unregister_chrdev_region(MKDEV(major, minor), 3);
OUT2:// 静态设备号申请失败,就要释放申请的字符驱动空间kfree(cdev);
OUT1:return ret;
}
static void __exit mycdev_exit(void)
{unsigned int i;//----------------------------------------销毁目录/设备信息-------------------------------//<1.设备销毁,现有目录后有设备,所以先销设备,后销目录for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}//<2.目录销毁class_destroy(cls);// 注销字符设备驱动对象cdev_del(cdev);// 释放设备号unregister_chrdev_region(MKDEV(major, minor), 3);// 释放对象空间kfree(cdev);//注销软中断号for (--i; i >= 0; i--){// 注销中断free_irq(key_irqnum[i], NULL);}// 灭灯for (i = 0; i < 3; i++){gpiod_set_value(desc[i], 0);// 注销GPIO编号gpiod_put(desc[i]);}
}module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

应用程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"int main(int argc,const char * argv[])
{int fd;int number;fd = open("/dev/mycdev0",O_RDWR);if(fd < 0){perror("error open ");return -1;}printf("打开设备文件成功\n");while(1){read(fd,&number,sizeof(number));printf("number=%d\n",number);}return 0;
}

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Lazada商品详情接口 获取Lazada商品详情数据 Lazada商品价格接

一、引言 随着电子商务的迅速发展和普及&#xff0c;电商平台之间的竞争也日趋激烈。为了提供更好的用户体验和更高效的后端管理&#xff0c;Lazada作为东南亚最大的电商平台之一&#xff0c;开发了一种商品详情接口&#xff08;Product Detail API&#xff09;。该接口允许第…

再写CentOS7升级OpenSSL-1.0.1U

本文在CentOS7.4以及TencentOS 2.4上测试通过。 原系统自带OpenSSL 1.0.2k-fips。 编译安装方法跟之前的没啥区别。 从官网下载1.0.1u版https://www.openssl.org/source/ 使用tar解包 tar xfz openssl-1.0.1u.tar.gz 依次执行如下&#xff1a; cd openssl-1.0.1u ./con…

Window基础命令

文章目录 查看哪些端口被禁用TCP协议删除开机启动项方案1方案2 查看哪些端口被禁用TCP协议 netsh interface ipv4 show excludedportrange protocoltcp删除开机启动项 方案1 列出所有启动项 bcdedit /enum仔细看你要删除的是哪一项&#xff08;看description&#xff09;&a…

Git企业开发控制理论和实操-从入门到深入(五)|标签管理

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

mysql数据库迁移

目录 背景迁移数据库 背景 公司有个项目&#xff0c;刚开始数据量不是大的时候&#xff0c;数据库和服务上的所有应用数据都放在一个旧小盘中&#xff0c;随着项目数据的增长&#xff0c;旧的磁盘被占满了&#xff0c;导致系统无法写入数据&#xff0c;我和同事排查了很长时间…

springboot服务端接口外网远程调试,并实现HTTP服务监听

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

为Android做一个ShowModal窗口

大家知道&#xff0c;用Delphi实现一个Form&#xff0c;并用ShowModal显示出来&#xff0c;在Android平台是非阻塞的&#xff0c;即执行了Form.ShowModal&#xff0c;代码会继续往下执行而不是等待&#xff0c;这跟在Windows平台是完全不一样的。如果我们需要类似阻塞的效果&am…

什么是ChatGPT水印,ChatGPT生成的内容如何不被检测出来,原理什么?

太长不看版 1. 什么是ChatGPT水印&#xff1f; ChatGPT水印是AI以伪随机方式生成的独特tokens序列。该序列用来作为水印&#xff0c;以区分AI生成内容和人类原创内容。 2. 如何规避ChatGPT水印&#xff1f; 一种规避方法是使用其他AI模型改写ChatGPT生成的文本。这会破坏水…

媒介盒子:医疗软文怎么写才能实现营销效果?

随着互联网的快速发展,医疗行业也逐渐意识到了网络营销的重要性。而作为网络营销的一种形式,医疗软文在传播医疗知识、宣传医疗品牌方面具有独特的优势。本文将从选题、内容、形式等多个方面进行探讨&#xff0c;如何写一篇有效的医疗营销软文&#xff1f; 1、选题非常关键 首…

mysql和mybatisPlus实现:datetime类型的字段范围查询

前提说明 数据库在存储数据时,我们为了精确一下时间,便会把改时间类型的字段设置为datetime类型; 在过滤数据库数据时,我们又需要对该字段进行一个范围的过滤 由此,便出现了这篇博客 datetime数据类型 在MySQL中,datetime数据类型用于保存日期和时间的值。它的格式为Y…

线性代数的学习和整理10:各种特殊类型的矩阵(草稿-----未完成 建设ing)

目录 1 图形化分类 1.1对称矩阵 1.2 梯形矩阵 1.3 三角矩阵 1.3.1 上三角矩阵 1.4 对角线矩阵 2 按各自功能分 2.1 等价矩阵 2.2 增广矩阵 2.3 伴随矩阵 2.4 正交矩阵 2.5 正交矩阵 2.6 相似矩阵 1 图形化分类 1.1对称矩阵 1.2 梯形矩阵 1.3 三角矩阵 1.3.1 上…

评估安全 Wi-Fi 接入:Cisco ISE、Aruba、Portnox 和 Foxpass

在当今不断变化的数字环境中&#xff0c;对 Wi-Fi 网络进行强大访问控制的需求从未像现在这样重要。各组织一直在寻找能够为其用户提供无缝而安全的体验的解决方案。 在本博客中&#xff0c;我们将深入探讨保护 Wi-Fi&#xff08;和有线&#xff09;网络的四种领先解决方案——…

理解HTTPS/TLS/SSL(一)基础概念+配置本地自签名证书

文章目录 没有HTTPS时的样子场景模拟WireShark的Capture Filter和Display Filter设置Capture Filter启动程序设置Display Filter过滤抓到的包 结论 关于为什么加密更简洁有力的回答对称加密和非对称加密和CA证书密钥交换对称加密非对称加密CA机构和证书如何解决客户端和CA机构之…

ChatGPT癌症治疗“困难重重”,真假混讲难辨真假,准确有待提高

近年来&#xff0c;人工智能在医疗领域的应用逐渐增多&#xff0c;其中自然语言处理模型如ChatGPT在提供医疗建议和信息方面引起了广泛关注。然而&#xff0c;最新的研究表明&#xff0c;尽管ChatGPT在许多领域取得了成功&#xff0c;但它在癌症治疗方案上的准确性仍有待提高。…

尚硅谷大数据项目《在线教育之离线数仓》笔记004

视频地址&#xff1a;尚硅谷大数据项目《在线教育之离线数仓》_哔哩哔哩_bilibili 目录 第9章 数仓开发之DWD层 P049 P050 P051 P052 P053 P054 P055 P056 P057 P058 P059 P060 P061 P062 P063 P064 P065 P066 P067 P068 P069 P070 第9章 数仓开发之DWD…

软件测试技术分享丨遇到bug怎么分析?

为什么定位问题如此重要&#xff1f; 可以明确一个问题是不是真的“bug” 很多时候&#xff0c;我们找到了问题的原因&#xff0c;结果发现这根本不是bug。原因明确&#xff0c;误报就会降低 多个系统交互&#xff0c;可以明确指出是哪个系统的缺陷&#xff0c;防止“踢皮球…

Jenkins自动化部署-Jenkins的安装

首先我们需要安装docker 安装 yum-utils包 yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 --skip-broken 设置镜像地址 yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce…

Midjourney 完整版教程(从账号注册到设计应用)

目录 一、Midjourney 介绍 二、Midjourney 的AI出图示例 三、手把手教你上手Midjourney 1、账号&初始化 1.1 账号注册登录 1.2 账号付费 1.3 账号初始化 2、Midjourney的基础设置 3、Midjourney 出图步骤。 (一)直接描述出图 (二)垫图生图。 4、Midjourney的…

squid服务器

目录 squid初识 安装squid代理 常用命令 主要配置文件 正向代理 环境配置 linux服务器设置 windows客户端设置 反向代理 环境配置 在web服务器配置服务 linux服务器配置 squid初识 含义&#xff1a;squid cache是一个流行的自由软件&#xff08;GNU通用公共许可证…

Docker 安装rabbitmq:3.12-management

拉取镜像&#xff1a; docker pull rabbitmq:3.12-management mkdir -p /usr/local/rabbitmq chmod 777 /usr/local/rabbitmq docker run -id --restartalways --namerabbitmq -v /usr/local/rabbitmq:/var/lib/rabbitmq -p 15672:15672 -p 5672:5672 -e RABBITMQ_DEFAULT_U…