【驱动开发】注册字符设备使用gpio设备树节点控制led三盏灯的亮灭
注册字符设备使用gpio设备树节点控制led三盏灯的亮灭
设备树:

头文件:
#ifndef __HEAD_H__
#define __HEAD_H__
typedef struct
{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR;
} gpio_t;
#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR 0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR 0X50000A28
// 构建开灯关灯的功能码
#define LED_ON _IOW('l', 1,int)
#define LED_OFF _IOW('l', 0,int)#endif
驱动程序:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/kdev_t.h>
#include "head.h"
struct class *cls;
struct device *dev;
struct resource *res;
unsigned int irqno;
struct device_node *dnode;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
int mycdev_open(struct inode *inode, struct file *file)
{unsigned int min = MINOR(inode->i_rdev); // 获取打开的文件的次设备号file->private_data = (void *)min;printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
ssize_t mycdev_read(struct file *file, char __user *user, size_t size, loff_t *lof)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
ssize_t mycdev_write(struct file *file, const char __user *user, size_t size, loff_t *lof)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{int min = (int)file->private_data; // 获取文件的次设备号switch (min){case 0: // LED1switch (cmd){case LED_ON: // 开灯gpiod_set_value(gpiono1, 1);break;case LED_OFF: // 关灯gpiod_set_value(gpiono1, 0);break;}break;case 1: // LED2switch (cmd){case LED_ON: // 开灯gpiod_set_value(gpiono2, 1);break;case LED_OFF: // 关灯gpiod_set_value(gpiono2, 0);break;}break;case 2: // LED3switch (cmd){case LED_ON: // 开灯gpiod_set_value(gpiono3, 1);break;case LED_OFF: // 关灯gpiod_set_value(gpiono3, 0);break;}break;}printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);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,.unlocked_ioctl = mycdev_ioctl,
};
int pdrv_probe(struct platform_device *pdev) // 当驱动和设备匹配成功后执行
{int ret,// 1.实例化字符设备驱动对象cdev = cdev_alloc();if (cdev == NULL){printk("申请字符设备驱动对象空间失败\n");ret = -EFAULT;goto OUT1;}printk("申请字符设备驱动对象空间成功\n");// 2.部分初始化字符设备驱动对象cdev_init(cdev, &fops);// 3.申请设备号if (major == 0) // 动态申请设备号{ret = alloc_chrdev_region(&devno, minor, 3, "mycdev");if (ret){printk("动态申请设备号失败\n");goto OUT2;}major = MAJOR(devno);minor = MINOR(devno);}else // 静态指定设备号{ret = register_chrdev_region(devno, 3, "mycdev");if (ret){printk("静态设备号失败\n");goto OUT2;}}printk("设备号申请成功\n");// 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");// 向上提交设备节点int i;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");res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL){printk("解析资源失败%d\n", __LINE__);return -ENOMEM;}irqno = platform_get_irq(pdev, 0);if (irqno < 0){printk("解析资源失败%d\n", __LINE__);return -ENOMEM;}printk("mem:%x irq:%d\n", res->start, irqno);// 使用gpio驱动dnode = of_find_node_by_path("/myplatform");if (dnode == NULL){printk("解析设备树节点失败\n");return -ENXIO;}// 解析出GPIO编号并申请gpiono1 = gpiod_get_from_of_node(pdev->dev.of_node, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono1)){printk("GPIO信息解析失败\n");return -PTR_ERR(gpiono1);}gpiono2 = gpiod_get_from_of_node(pdev->dev.of_node, "led2-gpio", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono2)){printk("GPIO信息解析失败\n");return -PTR_ERR(gpiono2);}gpiono3 = gpiod_get_from_of_node(pdev->dev.of_node, "led3-gpio", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono3)){printk("GPIO信息解析失败\n");return -PTR_ERR(gpiono3);}/*gpiod_set_value(gpiono1,1);gpiod_set_value(gpiono2,1);gpiod_set_value(gpiono3,1);*/printk("GPIO信息解析成功\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;
}
int pdrv_remove(struct platform_device *pdev) // 当设备和驱动分离时执行
{// 释放GPIO信息gpiod_put(gpiono1);gpiod_put(gpiono2);gpiod_put(gpiono3);// 销毁节点信息int i;for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}// 销毁目录class_destroy(cls);// 注销驱动unregister_chrdev(major, "mychrdev");return 0;
}
// 构建设备树匹配表
struct of_device_id oftable[] = {{.compatible = "hqyj,myplatform",},{.compatible = "hqyj,myplatform1",},{}, // 防止数组越界
};
// 1.分配驱动信息对象
struct platform_driver pdrv = {.probe = pdrv_probe,.remove = pdrv_remove,.driver = {.name = "bbbbb", // 驱动名.of_match_table = oftable,},
};
// 一键注册宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");
应用程序:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "head.h"int main(int argc, char const *argv[])
{int a, b;int fd;while (1){// 从中断获取我们想实现的功能功能printf("请选择要控制的灯:0-LED1,1-LED2,2-LED3\n");scanf("%d", &a);switch (a){case 1:fd = open("/dev/mycdev0", O_RDWR);break;case 2:fd = open("/dev/mycdev1", O_RDWR);break;case 3:fd = open("/dev/mycdev2", O_RDWR);break;}if (fd < 0){printf("打开设备文件失败\n");return -1;}printf("打开设备文件成功\n");printf("请输入想要实现的功能 ");printf("0(关灯)1(开灯)\n");printf("请输入>>>");scanf("%d", &b);switch (b){case 1:ioctl(fd, LED_ON, &b);break;case 0:ioctl(fd, LED_OFF, &b);break;}}close(fd);return 0;
}


相关文章:
【驱动开发】注册字符设备使用gpio设备树节点控制led三盏灯的亮灭
注册字符设备使用gpio设备树节点控制led三盏灯的亮灭 设备树: 头文件: #ifndef __HEAD_H__ #define __HEAD_H__ typedef struct {unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int OD…...
面向制造企业的持续发展,2023数字化工单管理系统创新篇章-亿发
面向制造企业的持续发展,2023数字化工单管理系统开创新篇章-亿发 随着制造业的持续发展,运维工单管理日益成为关键环节,它设计客户管理、设备维护、服务商合作等多个业务领域,对运营效率和服务质量有着重要影响。然而,…...
mysql 元数据锁 MDL读锁与MDL写锁
事务一开启事务 begin; select * from tablename;--相当于加了MDL读锁 此时事务2执行alter table tablename add ... --会发生修改阻塞 commit; --提交事务 释放MDL读锁 此时事务二修改成功 如果事务一执行做dml操作,操作期间将加MDL写锁...
批量预处理哨兵2影像
批量预处理哨兵2影像 最近下载70多景哨兵2影像,平均每个影像在cmd中处理时间都需要半个小时。算下来我一景一景手动处理需要37个小时左右,每天在电脑前待8个小时也要4天多,很浪费时间。如果能够批处理,不需要我手动做的话&#x…...
Unity地面交互效果——2、动态法线贴图实现轨迹效果
Unity引擎动态法线贴图制作球滚动轨迹 大家好,我是阿赵。 之前说了一个使用局部UV采样来实现轨迹的方法。这一篇在之前的基础上,使用法线贴图进行凹凸轨迹的绘制。 一、实现的目标 先来回顾一下,上一篇最终我们已经绘制了一个轨迹的贴图…...
视频剪辑达人教您:如何运用嵌套合并技巧制作固定片尾
在视频剪辑的过程中,嵌套合并技巧是一种非常实用的技术,可以帮助您将多个素材叠加在一起,制作出更加丰富多彩的视频。本文将由视频剪辑达人为您详细介绍如何运用云炫AI智剪嵌套合并技巧制作固定片尾,让您的视频剪辑水平更上一层楼…...
【腾讯云 TDSQL-C Serverless 产品体验】TDSQL-C MySQL Serverless最佳实践
一、引言: 随着云计算技术的不断发展,越来越多的企业开始选择将自己的数据库部署在云上,以更好了的支持企业数字化转型以及业务创新,在这个过程中,很多客户会遇到这样一个问题,业务会存在高峰期和低谷期&a…...
SQLyog连接数据库报plugin caching_sha2_password could not be loaded......解决方案
问题描述 问题分析 因为MySQL新版默认使用caching_sha2_password作为身份验证的插件,而旧版本使用的是mysql_native_password。当出现plugin caching_sha2_password could not be loaded报错,我们更换为旧版本 如何解决 先使用cmd命令登录MySQL&a…...
linux应急排查
常用命令 查看登录用户和活动 whoami:显示当前登录用户的用户名。 w:显示当前登录到系统上的用户列表和他们正在执行的命令。 last:显示最近登录到系统的用户列表、登录时间和来源IP地址。 ps aux:列出当前正在运行的所有进程&…...
Apache POI及easyExcel读取及写入excel文件
目录 1.excel 2.使用场景 3.Apache POI 4.easyExcel 5.总结 1.excel excel分为两版,03版和07版。 03版的后缀为xls,最大有65536行。 07版的后缀为xlsx,最大行数没有限制。 2.使用场景 将用户信息导出到excel表格中。 将excel中的数…...
为什么写作
1记录生活,表达自己的想法和情感,提高沟通能力。 2年轻的时候就有写作的意愿,一直未动笔。 3想突破自己看看自己能写到什么程度。锻炼自己更好组织思路,提高逻辑思维能力。 4给自己的生活增添一些爱好,更好地理解和…...
python基于VGG19实现图像风格迁移
目录 1、原理 2、代码实现 1、原理 图像风格迁移是一种将一张图片的内容与另一张图片的风格进行合成的技术。 风格(style)是指图像中不同空间尺度的纹理、颜色和视觉图案,内容(content)是指图像的高级宏观结构。 实…...
BoredHackerBlog: Cloud AV RT日记
目录 信息搜集 WEB漏洞攻击 拿shell 信息搜集 首先ifconfig查看自己IP, netdiscover查看同网段下主机 第三个应该是目标靶机。用nmap查看靶机开放端口: 开放22和8080,看看8080开的啥服务 WEB漏洞攻击 看到让我们输入邀请码。有输入框的第…...
数据结构之“初窥门径”
目录 前言: 一,数据结构起源 二,基本概念和术语 2.1数据 2.2数据元素 2.3数据项 2.4数据对象 2.5数据结构 三,逻辑结构与物理结构 3.1逻辑结构 3.1.1集合结构 3.1.2线性结构 3.1.3树形结构 3.1.4图形结构 3.2物理结…...
css:transform实现平移、旋转、缩放、倾斜元素
目录 文档语法示例旋转元素 transform-rotate旋转过渡旋转动画 参考文章 文档 https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform 语法 /* Keyword values */ transform: none;/* Function values */ transform: matrix(1, 2, 3, 4, 5, 6); transform: translate…...
如何理解AutoGPT
AutoGPT和GPT-4都是OpenAI公司的产品。AutoGPT是一个实验性开源应用程序,展示了GPT-4语言模型的能力。GPT-4是OpenAI研发的人工智能语言模型。 AutoGPT在GitHub主页上有151k星(151k星代表了151,000个用户点赞了该项目),AutoGPT获…...
【网络知识必知必会】聊聊网络层IP协议
文章目录 前言IP 协议格式总结 前言 在之前的博文中, 我们聊过了传输层中的两个重点协议 TCP 和 UDP, 本文我们再来聊聊网络层中的一个协议IP, 简单认识一下 IP 协议格式. IP 协议与 TCP 协议的复杂度也不妨多让, 不过我们在这里只是简单的聊一聊 IP 协议的报文格式就行, 毕竟…...
66. 加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。 示例 1: 输入: digits …...
逻辑(css3)_强制不换行
需求 如上图做一个跑马灯数据,时间、地点、姓名、提示文本字数都不是固定的。 逻辑思想 个人想法是给四个文本均设置宽度,不然会出现不能左对齐的现象。 此时四个文本均左对齐, 垂直排列样式也比较好看,但是出现一个缺点&#…...
营收净利双降、股价下跌四成,敷尔佳带伤闯关“双11”
今年双11预售已经开启,敷尔佳在天猫、抖音等电商平台火热营销;营销热业绩冷,敷尔佳的三季报不及预期。 10月23日,哈尔滨敷尔佳科技发展有限公司(下称“敷尔佳”,301371SZ)公布2023年三季报,其三季度营收净…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...
