嵌入式:驱动开发 Day9

作业:通过platform总线驱动实现

a.应用程序通过阻塞的io模型来读取number变量的值
b.number是内核驱动中的一个变量
c.number的值随着按键按下而改变(按键中断) 例如number=0 按下按键number=1 ,再次按下按键number=0
d.在按下按键的时候需要同时将led1的状态取反
e.驱动中需要编写字符设备驱动
f.驱动中需要自动创建设备节点
g.这个驱动需要的所有设备信息放在设备树的同一个节点中

驱动程序:my_platform.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/wait.h>struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
module_param(major, uint, 0664); //方便命令行传递major的值
struct class *cls;
struct device *dev;
struct resource *res;
unsigned int irqno;
struct gpio_desc *gpiono;
wait_queue_head_t wq_head; //定义一个等待队列头
unsigned int number = 0;
unsigned int condition = 0;//定义中断处理函数
irqreturn_t key_handler(int irq, void *dev)
{gpiod_set_value(gpiono, !gpiod_get_value(gpiono));if (number == 0){number = 1;condition = 1;wake_up_interruptible(&wq_head);}else{number = 0;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;//判断IO方式if (file->f_flags & O_NONBLOCK) //非阻塞{}else{                                                 //阻塞wait_event_interruptible(wq_head, condition); //先检查condition再将进程休眠}ret = copy_to_user(ubuf, &number, size);if (ret){printk("copy_to_user err\n");return -EIO;}condition = 0; //下一次硬件数据没有就绪return 0;
}ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{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,
};//封装probe函数
int pdrv_probe(struct platform_device *pdev)
{//初始化等待队列init_waitqueue_head(&wq_head);int ret;//1.为字符设备驱动对象申请空间cdev = cdev_alloc();if (cdev == NULL){printk("申请字符设备驱动对象空间失败\n");ret = -EFAULT;goto out1;}printk("申请字符设备驱动对象空间成功\n");//2.初始化字符设备驱动对象cdev_init(cdev, &fops);printk("初始化字符设备驱动对象成功\n");//3.申请设备号if (major > 0) //静态指定设备号{ret = register_chrdev_region(MKDEV(major, minor), 3, "myled");if (ret){printk("静态申请设备号失败\n");goto out2;}}else if (major == 0){ //动态申请设备号ret = alloc_chrdev_region(&devno, minor, 3, "myled");if (ret){printk("动态申请设备号失败\n");goto out2;}major = MAJOR(devno); //获取主设备号minor = MINOR(devno); //获取次设备号}printk("申请设备号成功\n");//4.注册字符设备驱动对象ret = cdev_add(cdev, MKDEV(major, minor), 3);if (ret){printk("注册字符设备驱动对象失败\n");goto out3;}printk("注册字符设备驱动对象成功\n");//向上提交目录信息cls = class_create(THIS_MODULE, "myled");if (IS_ERR(cls)){printk("向上提交目录失败\n");ret = -PTR_ERR(cls);goto out4;}printk("向上提交目录成功\n");//向上提交设备节点信息int i;for (i = 0; i < 3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);if (IS_ERR(dev)){printk("向上提交设备节点信息失败\n");ret = -PTR_ERR(dev);goto out5;}}printk("向上提交设备信息成功\n");//platform//获取MEM类型的资源res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL){printk("获取MEM类型资源失败\n");return -ENXIO;}//获取中断类型的资源irqno = platform_get_irq(pdev, 0);if (irqno < 0){printk("获取中断类型资源失败\n");return -ENXIO;}//设备树匹配成功后,设备树结点指针可以通过pdev->dev.of_node获取//基于设备树节点信息获取gpio_desc对象指针gpiono = gpiod_get_from_of_node(pdev->dev.of_node, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono)){printk("解析GPIO管脚信息失败\n");return -ENXIO;}printk("解析GPIO管脚信息成功\n");//注册按键中断ret = request_irq(irqno, key_handler, IRQF_TRIGGER_FALLING, "key_init", NULL);if (ret < 0){printk("注册按键%d中断失败\n", i);return ret;}printk("注册按键中断成功\n");return 0;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;
}//封装remove函数
int pdrv_remove(struct platform_device *pdev)
{//注销中断free_irq(irqno, NULL);//释放GPIO信息gpiod_put(gpiono);int i;//释放设备节点信息for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}//销毁目录class_destroy(cls);//注销字符设备驱动对象cdev_del(cdev);//释放设备号unregister_chrdev_region(MKDEV(major, minor), 3);//释放设备驱动对象空间kfree(cdev);return 0;
}//构建设备树匹配表
struct of_device_id oftable[] = {{.compatible = "hqyj,myplatform"},{}, //防止数组越界
};//定义platform驱动信息对象并初始化
struct platform_driver pdrv = {.probe = pdrv_probe,.remove = pdrv_remove,.driver = {.name = "bbbbb",.of_match_table = oftable, //用于设备树匹配},
};//一键注册platform宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

应用程序:test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
int main(){unsigned int number;int fd = open("/dev/myled0", O_RDWR);if(fd < 0){printf("设备文件打开失败\n");exit(-1);}while(1){read(fd, &number, sizeof(number));printf("number = %d\n", number);}close(fd);return 0;
}

实验现象:

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

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

相关文章

Python 公里与海里换算

""" 公里与海里换算知识点&#xff1a;1、换算公式&#xff1a;海里 公里 / 1.8522、input()、print()函数3、变量类型转换&#xff0c;整形int与字符串str转换&#xff0c;可以用type()函数验证4、字符串拼接&#xff0c;例如&#xff1a;123 456 1234565、…

Vue3快速上手

1.Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff09;耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址&#xff1a;Release v3.0.0 One Piece vuejs/core GitHub 2.Vue3带…

搜款网VVIC根据ID取商品详情 API 关键词搜索商品列表

搜款网是一家服装批发平台&#xff0c;提供多个品牌和供应商的服装、鞋子、箱包等商品供采购者选择&#xff0c;为了获取商品详情&#xff0c;您需要使用搜款网的API接口。 建议您联系搜款网的客服或开发者&#xff0c;以获取更多关于API接口的信息&#xff0c;包括使用方法、…

数据标准化

1、均值方差标准化(Z-Score标准化) 计算过程&#xff1a; 对每个属性/每列分别进行一下操作&#xff0c;将数据按属性/按列减去其均值&#xff0c;并除以其方差&#xff0c;最终使每个属性/每列的所有数据都聚集在均值为0&#xff0c;方差为1附近。 公式&#xff1a;(x-mean(x…

M-LAG简介

定义 M-LAG&#xff08;Multichassis Link Aggregation Group&#xff09;即跨设备链路聚合组&#xff0c;是一种实现跨设备链路聚合的机制&#xff0c;将一台设备与另外两台设备进行跨设备链路聚合&#xff0c;从而把链路可靠性从单板级提高到了设备级&#xff0c;组成双活系…

Linux CentOS7 wc命令

wc命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出。 录入 man wc 可以查看相关信息 基本语法&#xff1a; wc [选项] 文件… 说明&#xff1a;该命令统计给定文件中的字节数、字数、行数。如果没有给出文件名&#xff0c;则从标准输入读取。wc同时也…

C语言进阶第三课-----------指针的进阶----------后续版

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

docker总结

Docker实用篇 0.学习目标 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署…

ddtrace 系列篇之 dd-trace-java 项目编译

dd-trace-java 是 Datadog 开源的 java APM 框架&#xff0c;本文主要讲解如何编译 dd-trace-java 项目。 环境准备 JDK 编译环境(三个都要&#xff1a;jdk8\jdk11\jdk17) Gradle 8 Maven 3.9 (需要 15G 以上的存储空间存放依赖) Git >2 (低于会出现一想不到的异常&#xf…

大语言模型之十-Byte Pair Encoding

Tokenizer 诸如GPT-3/4以及LlaMA/LlaMA2大语言模型都采用了token的作为模型的输入输出&#xff0c;其输入是文本&#xff0c;然后将文本转为token&#xff08;正整数&#xff09;&#xff0c;然后从一串token&#xff08;对应于文本&#xff09;预测下一个token。 进入OpenAI官…

Learn Prompt-Prompt 高级技巧:MetaGPT

MetaGPT是一项引起广泛关注的研究成果&#xff0c;它引入了一个将人工工作流程与多智能体协作无缝集成的框架。通过将标准化操作&#xff08;SOP&#xff09; 程序编码为提示&#xff0c;MetaGPT确保解决问题时采用结构化方法&#xff0c;从而减少出错的可能性。 &#x1f389…

【深度学习】ONNX模型快速部署【入门】

【深度学习】ONNX模型快速部署【入门】 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】ONNX模型快速部署【入门】前言搭建打包环境打包可执行文件总结 前言 之前的内容已经尽可能简单、详细的介绍CPU【Pytorch2ONNX】和GPU【Pyto…

蓝桥杯打卡Day12

文章目录 接龙数列冶炼金属 一、接龙数列OJ链接 本题思路:本题是一道经典的dp问题&#xff0c;设第i个数的首位数字是first&#xff0c; 末位数字是last。因为第i个数只可能加到一个以first结尾的接龙数列中使得这个接龙数列长度加1并且结尾数字变成last.所以状态转移方程为d…

设计模式_解释器模式

解释器模式 案例 角色 1 解释器基类 &#xff08;BaseInterpreter&#xff09; 2 具体解释器1 2 3... (Interperter 1 2 3 ) 3 内容 (Context) 4 用户 (user) 流程 (上下文) ---- 传…

Redis 面试题——缓存穿透、缓存击穿和缓存雪崩

目录 1.缓存穿透2.缓存击穿3.缓存雪崩4.总结 参考文章&#xff1a; 缓存实战&#xff08;1&#xff09;缓存雪崩、缓存击穿和缓存穿透入门简介及解决方案 1.缓存穿透 &#xff08;1&#xff09;问题描述&#xff1a;缓存穿透是指在高并发场景下&#xff0c;大量的请求访问一个…

23种设计模式汇总详解

设计原则 中文名称英文名称含义解释单一职责原则Single Responsibility Principle(SRP)任何一个软件模块都应该只对某一类行为者负责一个类只干一件事&#xff0c;实现类要单一开闭原则Open-Close Principle(OCP)软件实体&#xff08;类、模块、函数等&#xff09;应该是可以扩…

ChatGpt介绍和国产ChatGpt对比

1.ChatGPT是美国OpenAI研发的聊天机器人程序&#xff0c;2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过理解和学习人类的语言来进行对话。 2.ChatGPT是一种基于自然语言处理的聊天机器人程序。它使用深度学习技术&#xff0c;通过对…

【Linux】常用工具(下)

Linux常用工具 一、Linux 项目自动化构建工具 - make/Makefile1. 依赖关系和依赖方法2. 伪目标3. make/Makefile 具有依赖性的推导能力&#xff08;语法扩展&#xff09;4. 编写一个进度条代码&#xff08;1&#xff09;缓冲区&#xff08;2&#xff09;\n 和 \r&#xff08;3&…

软件测试-BUG

软件测试-BUG 1.如何合理创建一个BUG 创建bug的要素&#xff1a; 软件的版本发现问题的环境发现问题的步骤预期结果实际结果 Bug报告&#xff1a; 软件版本&#xff1a;Google Chrome浏览器&#xff08;具体版本号&#xff09; 发现问题环境&#xff1a;在Windows 10操作系统…

ASO优化之如何给应用选择竞争对手

在选择竞争对手过程中&#xff0c;最常见的错误之一是没有考虑到自己的应用与同一行业的其他应用相比的范围。例如如果我们刚刚发布了一个应用程序&#xff0c;那么最好的办法就是专注于研究和自己同一级别的应用。 1、研究主要关键词。 首先选择5到10个可以定义产品类型的主要…