通过platform总线驱动框架编写LED灯的驱动,编写应用程序测试,发布到CSDN

news2024/10/7 6:42:44

效果图

设备树代码

myplatform{
		compatible = "hqyj,myplatform";
	 	led1-gpio=<&gpioe 10 0>;
       		led2-gpio=<&gpiof 10 0>;
        	led3-gpio=<&gpioe 8 0>;           
		 interrupt-parent = <&gpiof>;
    		interrupts=<9 0>;
		reg=<0X12345678 0X400>;
	}; 

应用程序

#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
#include<sys/ioctl.h>
 
//创建功能码
#define LED_ON _IOW('l',1,int)  
#define LED_OFF _IOW('l',0,int)
 
int main(int argc, char const *argv[])
{
    int a,b;
    int fd=open("/dev/myled0",O_RDWR);
    if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while(1)
    {
        //从终端读取
        printf("请输入要实现的功能\n");
        printf("0(关灯) 1(开灯)\n");
        printf("请输入>");
        scanf("%d",&a);
        printf("请输入要控制的灯\n");
        printf("1(LED1) 2(LED2) 3(LED3)\n");
        printf("请输入>");
        scanf("%d",&b);
        switch(a)
        {
            case 1:
                ioctl(fd,LED_ON,b);
                break;
            case 0:
                ioctl(fd,LED_OFF,b);
                break;
        }
    }
 
    
    close(fd);
 
    return 0;
}

驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
 
//主设备号
int major;
 
//用于上传目录和设备节点信息
struct class *cls;
struct device *device;
 
// led设备号
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
 
// 创建功能码
#define LED_ON _IOW('l', 1, int)
#define LED_OFF _IOW('l', 0, int)
 
// ioctl函数,用于控制led设备
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd)
    {
    case LED_ON:
        switch (arg)
        {
        case 1:
            gpiod_set_value(gpiono1, 1);
            break;
        case 2:
            gpiod_set_value(gpiono2, 1);
            break;
        case 3:
            gpiod_set_value(gpiono3, 1);
            break;
        }
        break;
    case LED_OFF:
        switch (arg)
        {
        case 1:
            gpiod_set_value(gpiono1, 0);
            break;
        case 2:
            gpiod_set_value(gpiono2, 0);
            break;
        case 3:
            gpiod_set_value(gpiono3, 0);
            break;
        }
 
        break;
    }
    return 0;
}
 
// 定义操作方法结构体变量并赋值
struct file_operations fops = {
    .unlocked_ioctl = mycdev_ioctl,
};
 
// 封装probe函数,当设备和驱动匹配成功之后执行
int pdrv_probe(struct platform_device *dev)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
 
    // 字符设备驱动注册
    major = register_chrdev(0, "mychrdev", &fops);
    if (major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功:major=%d\n", major);
    // 向上提交目录
    cls = class_create(THIS_MODULE, "mychrdev");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录成功\n");
    // 向上提交设备节点信息
    int i; // 向上提交三次设备节点信息
    for (i = 0; i < 3; i++)
    {
        device = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
        if (IS_ERR(dev))
        {
            printk("向上提交设备节点失败\n");
            return -PTR_ERR(dev);
        }
    }
 
    printk("向上提交设备节点成功\n");
 
    // 解析LED1的gpio编号
    gpiono1 = gpiod_get_from_of_node(dev->dev.of_node, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);
    if (gpiono1 == NULL)
    {
        printk("解析led1对应gpio编号失败\n");
        return -ENXIO;
    }
    printk("解析led1对应gpio编号成功\n");
    // 解析LED1的gpio编号
    gpiono2 = gpiod_get_from_of_node(dev->dev.of_node, "led2-gpio", 0, GPIOD_OUT_LOW, NULL);
    if (gpiono2 == NULL)
    {
        printk("解析led2对应gpio编号失败\n");
        return -ENXIO;
    }
    printk("解析led2对应gpio编号成功\n");
    // 解析LED1的gpio编号
    gpiono3 = gpiod_get_from_of_node(dev->dev.of_node, "led3-gpio", 0, GPIOD_OUT_LOW, NULL);
    if (gpiono3 == NULL)
    {
        printk("解析led3对应gpio编号失败\n");
        return -ENXIO;
    }
    printk("解析led3对应gpio编号成功\n");
 
    return 0;
}
// 封装remove函数,用于驱动和设备卸载时执行
int pdrv_remove(struct platform_device *dev)
{
    // 销毁设备节点信息
    device_destroy(cls, MKDEV(major, 0));
 
    // 销毁设备节点信息
    int i;
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
 
    // 释放gpio编号
    gpiod_put(gpiono1);
    gpiod_put(gpiono2);
    gpiod_put(gpiono3);
 
    // 销毁目录
    class_destroy(cls);
    // 注销字符设备驱动
    unregister_chrdev(major, "mychrdev");
 
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
// 构建用于匹配的设备树表
struct of_device_id oftable[] = {
    {
        .compatible = "hqyj,myplatform",
    },
    {/* end node */}, // 防止数组越界
};
// 分配驱动对象并初始化
struct platform_driver pdrv = {
    .probe = pdrv_probe,
    .remove = pdrv_remove,
    .driver = {
        .name = "bbbbb",
        .of_match_table = oftable, // 设置设备树匹配
    },
 
};
// 一键注册宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

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

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

相关文章

idea在工具栏中显示快速创建包和类的图标

一、效果图 点击需要创建包或者类的位置&#xff0c;在点击对用的图标就可以快速创建类或者包了。 二、设置 步骤一 View-->Appearance-->Toolbar 步骤二 File-->Settings-->Appearance & Behavior-->Menus and Toolbars-->Main Toolbar-->----…

Vue3 (unplugin-auto-import自动导入的使用)

安装 参考链接 npm i -D unplugin-auto-importvite.config.ts里面配置 import AutoImport from unplugin-auto-import/viteAutoImport({imports:[ vue,vue-router]})重新运行项目会生成一个auto-imports.d.ts的文件 /* eslint-disable */ /* prettier-ignore */ // ts-nochec…

在Ubuntu系统下搭建TDengine集群

目录 一、Ubuntu虚拟机创建 二、系统相关配置 1、设置系统hostname 2、网络配置及IP规划 3、配置FQDN&#xff08;etc/hosts&#xff09; 4、服务端口设置 三、TDengine server安装 1、服务安装 2、修改配置 3、启动taosd 4、服务卸载 四、客户端安装 1、client安…

密评技术要求实施详解:每一步都关键

密评简介 密评定义&#xff1a;全称商用密码应用安全性评估, 是对采用商用密码技术、产品和服务集成建设的网络和信息系统密码应用的合规性、正确性、有效性进行评估的活动。 评测依据&#xff1a;GB/T 39786-2021《信息安全技术 信息系统密码应用基本要求》。 密评对象&…

(done) 什么是特征值和特征向量?如何求特征值的特征向量 ?如何判断一个矩阵能否相似对角化?

什么是齐次方程&#xff1f; https://blog.csdn.net/shimly123456/article/details/136198159 行列式和是否有解的关系&#xff1f; https://blog.csdn.net/shimly123456/article/details/136198215 特征值和特征向量 参考视频&#xff1a;https://www.bilibili.com/video/BV…

【MATLAB】CEEMD_ MFE_SVM_LSTM 神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 CEEMD_MFE_SVM_LSTM神经网络时序预测算法是一种结合了多种先进技术的复杂预测方法&#xff0c;旨在提高时序预测的准确性和稳定性。下面是对该算法的详细介绍&#xff1a; CEEMD&#xff…

基于Java+SpringBoot+Vue前后端分离婚纱影楼管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容&#xff1a;SpringBoot、Vue、SSM、HLM…

【监督学习之决策树和随机森林】

曾梦想执剑走天涯&#xff0c;我是程序猿【AK】 目录 简述概要知识图谱决策树&#xff08;Decision Tree&#xff09;随机森林&#xff08;Random Forest&#xff09; 简述概要 了解决策树和随机森林 知识图谱 决策树和随机森林都是机器学习中常用的算法&#xff0c;它们在处…

.net core wbeapi 关于swagger的配置

当创建好一个webapi之后&#xff0c;在Program.cs中注释掉原本的AddSwaggerGen&#xff0c;修改为如下配置 Program.cs //builder.Services.AddSwaggerGen();builder.Services.AddSwaggerGen(options >{options.SwaggerDoc("v1", new OpenApiInfo{Version "…

利用docker一键部署LLaMa到自己的Linux服务器,有无GPU都行、可以指定GPU数量、支持界面对话和API调用,离线本地化部署包含模型权重合并

利用docker一键部署LLaMa到自己的Linux服务器,有无GPU都行、可以指定GPU数量、支持界面对话和API调用,离线本地化部署包含模型权重合并。两种方式实现支持界面对话和API调用,一是通过搭建text-generation-webui。二是通过llamma.cpp转换模型为转换为 GGUF 格式,使用 quanti…

介绍 CI / CD

目录 一、介绍 CI / CD 1、为什么要 CI / CD 方法简介 1、持续集成 2、持续交付 3、持续部署 2、GitLab CI / CD简介 3、GitLab CI / CD 的工作原理 4、基本CI / CD工作流程 5、首次设置 GitLab CI / CD 6、GitLab CI / CD功能集 一、介绍 CI / CD 在本文档中&#x…

.NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2

前言 很多同学都不愿给电脑设动态壁纸&#xff0c;其中有个重要原因就是嫌它占资源过多。今天大姚分享一个.NET开源、免费&#xff08;MIT license&#xff09;的一个小而快并且功能强大的 Windows 动态桌面软件&#xff0c;支持视频和网页动画播放&#xff1a;DreamScene2。 …

【人脸朝向识别与分类预测】基于LVQ神经网络

课题名称&#xff1a;基于LVQ神经网络的人脸朝向识别分类 版本日期&#xff1a;2024-02-20 运行方式&#xff1a;直接运行GRNN0503.m文件 代码获取方式&#xff1a;私信博主或 企鹅号:491052175 模型描述&#xff1a; 采集到一组人脸朝向不同角度时的图像&#xff0c;图像…

恒创科技:租用香港服务器,可以为企业跨境电商提供哪些支撑?

租用香港服务器可以为企业跨境电商提供以下支撑&#xff1a; 快速访问速度&#xff1a;香港位于亚洲的中心地带&#xff0c;连接中国大陆和国际市场&#xff0c;租用香港服务器可以提供优化的跨境访问体验&#xff0c;缩短访问延迟&#xff0c;提升网站加载速度&#xff0c;降低…

HarmonyOS Stage模型 应用配置文件讲解

好&#xff0c;上文 HarmonyOS Stage模型基本概念讲解 中&#xff0c;我们简单讲解了HarmonyOS 中 Stage模型的基本概念 那么 我们继续学习Stage模型的相关知识 上文之后 我们肯定对它的概念和基本结构 有了一个了解 那么 我们就来看一下 基于Stage模型 它里面一些基本的配置文…

Jenkins 的全局配置 SSH(6)

用于打通构建机和远程主机的ssh通路 前提说明&#xff1a;需要将构建机中&#xff0c;root账户和jenkins账户的公钥同步到远程主机的authorized_keys中&#xff08;配置jenkins管理代码部署&#xff0c;配置root控制远程服务权限&#xff09; A - ECS:&#xff08;测试或正式或…

React18源码: reconcliler启动过程

Reconcliler启动过程 Reconcliler启动过程实际就是React的启动过程位于react-dom包&#xff0c;衔接reconciler运作流程中的输入步骤.在调用入口函数之前&#xff0c;reactElement(<App/>) 和 DOM对象 div#root 之间没有关联&#xff0c;用图片表示如下&#xff1a; 在启…

液晶手写板可显字原理

前言 最近买了一个乐写可视手写板用于代替纸笔,手写板自带一个电磁笔,写在手写板上可以显现笔迹,然后可以用于电脑的笔迹书写,计算公式更加符合纸笔手感,那么这种手写板可显现笔迹的原理是什么? 显像原理 对于液晶可显现笔迹的手写板,其表面由三层组成: 顶层是透明的硬塑料…

论文笔记:利用词对比注意增强预训练汉字表征

整理了 ACL2020短文 Enhancing Pre-trained Chinese Character Representation with Word-aligned Att&#xff09;论文的阅读笔记 背景模型实验 论文地址&#xff1a;论文 背景 近年来&#xff0c;以 BERT 为代表的预训练模型在 NLP 领域取得取得了非常显著的效果。但是&…

关于git子模块实践(一)

背景 在日常项目开发中&#xff0c;随着项目的迭代&#xff0c;不可避免的是主项目会引入到很多三方库&#xff0c;或者自研的一些模块。有一种场景&#xff0c;就是这些模块&#xff0c;是随着开发而进行迭代&#xff0c;且多个项目公用的&#xff0c;这种情况&#xff0c;在…