(Linux驱动学习 - 9).设备树下platform的LED驱动

一.platform相关结构体与函数

1.匹配列表 - struct of_device_id

struct of_device_id
{char name[32];char type[32];/* compatible 很重要,需要与设备树节点的 compatible 属性一致,才能匹配 */char compatible[128];        const void *data;
};

2.device_driver

struct device_driver 
{/* 设备名字,在不用设备树的情况下可以使用 name 匹配 */const char *name;            struct bus_type *bus;struct module *owner;const char *mod_name;         /* used for built-in modules */bool suppress_bind_attrs;     /* disables bind/unbind via sysfs *//* 设备树下的匹配列表结构体 */const struct of_device_id *of_match_table;const struct acpi_device_id *acpi_match_table;int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p;
};

3.平台驱动结构体 - struct platform_driver

struct platform_driver 
{/* 匹配成功后此函数会执行,将注册字符设备等内容放入这个函数,例如注册字符设备驱动、添加cdev、创建类等 */int (*probe)(struct platform_device *);/* 当关闭 platform 设备驱动的时候此函数会执行,把以前在 exit 中要做的事情放到这个里面,如删除cdev、注销设备号等 */int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);/* 用于匹配设备和 platform 驱动 */struct device_driver driver;const struct platform_device_id *id_table;bool prevent_deferred_probe;
};

4.声明设备匹配列表 - MODULE_DEVICE_TABLE

函数原型

/*
*    @description:         : 声明匹配列表
*    @param - type         : 设备类型,设备树下的设备就传入 of
*    @param - xxx_of_match : 匹配列表结构体
*/
MODULE_DEVICE_TABLE(type,struct of_device_id xxx_of_match);

5.向Linux内核注册一个 platform 驱动 - platform_driver_register

函数原型:

/*** @description:            向Linux内核注册一个 platform 驱动* @param - driver  :       要注册的 platform 驱动* @return          :       成功时返回(0),失败则返回(负数)*/
int platform_driver_register(struct platform_driver *driver)

6.卸载 platform 驱动 - platform_driver_unregister

函数原型

/*** @description:            卸载 platform 驱动* @param - drv     :       要卸载的 platform 驱动* @return          :       无*/
void platform_driver_unregister(struct platform_driver *drv)

二.platform下的LED实验

1.设备树

(1).流程图

        注意:compatible 属性部分要与匹配列表中的 compatible 部分一致

(2).设备树代码

2.驱动部分

(1).流程图

(2).驱动代码

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <linux/semaphore.h>
#include <linux/fs.h>#define LEDDEV_CNT  1               /* 设备号个数 */
#define LEDDEV_NAME "dtsplatled"    /* 设备名字 */
#define LEDOFF      0               /* 关灯 */
#define LEDON       1               /* 开灯 *//* leddev 设备结构体 */
struct leddev_dev
{dev_t devid;                /* 设备号 */struct cdev cdev;           /* cdev */struct class *class;        /* 类 */struct device *device;      /* 设备 */int major;                  /* 主设备号 */int minor;                  /* 次设备号 */struct device_node *node;   /* LED设备结点 */int led0;                   /* LED 灯的 GPIO 编号 */
};/* led 设备 */
struct leddev_dev leddev;/*
* @description : LED 打开/关闭
* @param - sta : LEDON(0) 打开 LED, LEDOFF(1) 关闭 LED
* @return : 无
*/
void led0_switch(u8 sta)
{if (sta == LEDON )gpio_set_value(leddev.led0, 0);else if (sta == LEDOFF)gpio_set_value(leddev.led0, 1);
}/*** @description:            打开设备* @param - inode   :       传递给驱动的 inode* @param - filp    :       要打开的文件,file结构体有个private_data的成员变量,一般在open的时候将private_data指向设备结构体* @return          :       成功时返回(0),失败时返回(其他值)*/
static int led_open(struct inode *inode,struct file *filp)
{/* 设置私有数据 */filp->private_data = &leddev;return 0;
}/*** @description:            向设备写数据* @param - filp    :       设备文件,表示打开的文件描述符* @param - buf     :       要写入设备的数据* @param - cnt     :       要写入的字节数* @param - offt    :       相对于文件首地址的偏移量* @return          :       成功时返回(成功写入的字节数),失败时返回(负值)*/
static ssize_t led_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt)
{int retvalue;unsigned char databuf[0];unsigned char ledstat;retvalue = copy_from_user(databuf,buf,cnt);if(0 > retvalue){printk("kernel write falied!\r\n");return -EFAULT;}ledstat = databuf[0];if(LEDON == ledstat){led0_switch(LEDON);}else if(LEDOFF == ledstat){led0_switch(LEDOFF);}return 0;
}/* 绑定设备操作函数 */
static struct file_operations led_fops = 
{.owner = THIS_MODULE,.open = led_open,.write = led_write,
};/*** @description:            platform 驱动的probe函数,当驱动与设备匹配以后此函数会执行* @param - dev     :       platform 设备* @return          :       成功时返回(0),失败时返回(负值) */
static int led_probe(struct platform_device *dev)
{printk("led driver and device was matched!\r\n");/* 一.设置 LED 所使用的 GPIO *//* 1.获取设备结点 */leddev.node = of_find_node_by_path("/gpioled");/* 2.得到 GPIO 编号 */leddev.led0 = of_get_named_gpio(leddev.node,"led-gpio",0);/* 3.申请 gpio */gpio_request(leddev.led0,"led0");/* 4.设置gpio默认输出为高电平,关闭 LED 灯 */gpio_direction_output(leddev.led0,1);/* 二.注册字符设备驱动 *//* 1.创建设备号 */if(leddev.major){leddev.devid = MKDEV(leddev.major,0);register_chrdev_region(leddev.devid,LEDDEV_CNT,LEDDEV_NAME);}else{alloc_chrdev_region(&leddev.devid,0,LEDDEV_CNT,LEDDEV_NAME);leddev.major = MAJOR(leddev.devid);printk("leddev major : %d\r\n",leddev.major);}/* 2.初始化 cdev */cdev_init(&leddev.cdev,&led_fops);/* 3.添加一个 cdev */cdev_add(&leddev.cdev,leddev.devid,LEDDEV_CNT);/* 4.创建类 */leddev.class = class_create(THIS_MODULE,LEDDEV_NAME);if(IS_ERR(leddev.class)){return PTR_ERR(leddev.class);}/* 5.创建设备 */leddev.device = device_create(leddev.class,NULL,leddev.devid,NULL,LEDDEV_NAME);if(IS_ERR(leddev.device)){return PTR_ERR(leddev.device);}return 0;
}/*** @description:            platform驱动的remove函数,移除platform驱动的时候会执行此函数* @param - dev     :       platform 设备* @return          :       成功时返回(0),失败时返回(负值)*/
static int led_remove(struct platform_device *dev)
{gpio_set_value(leddev.led0,1);              //卸载驱动的时候关闭 LED 灯/* 注销字符设备驱动 */cdev_del(&leddev.cdev);unregister_chrdev_region(leddev.devid,LEDDEV_CNT);device_destroy(leddev.class,leddev.devid);class_destroy(leddev.class);return 0;
}/* 匹配列表 */
static struct of_device_id led_of_match[] =
{{.compatible = "atkalpha-gpioled"},{}
};/* platform 驱动结构体 */
static struct platform_driver led_driver = 
{.driver = {.name = "imx6ul-led",               //驱动名字,用于无设备树时的匹配.of_match_table = led_of_match,     //设备树匹配列表},.probe = led_probe,.remove = led_remove,
};/*** @description:            驱动入口函数* @param -         :       无* @return          :       */
static int __init leddriver_init(void)
{return platform_driver_register(&led_driver);
}/*** @description:            驱动出口函数* @param           :       无*/
static void __exit leddriver_exit(void)
{platform_driver_unregister(&led_driver);
}module_init(leddriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kaneki");

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

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

相关文章

IOT-Tree连接西门子PLC S7 200 Smart竟然如此简单

最近一个项目需要把用户现场控制柜接入到云端&#xff0c;控制柜使用西门子PLC Smart 200 SR40型号&#xff0c;已经运行多年&#xff0c;PLC通过以太网接口对接一个触摸屏。 按照我以往的经验&#xff0c;觉得触摸屏以太网接口已经被占用&#xff0c;那么只能通过剩余的RS485…

视频剪辑软件推荐电脑版:这5款剪辑软件不容错过!

在视频剪辑领域&#xff0c;选择合适的软件至关重要。不同的软件各有千秋&#xff0c;有的简单易用&#xff0c;适合新手快速上手&#xff1b;有的功能强大&#xff0c;适合专业团队进行深度编辑。以下是一些电脑版视频剪辑软件的推荐&#xff0c;涵盖了从新手到专业级别的不同…

智能电子价签:助力零售效率升级的关键

在竞争日益激烈的零售市场&#xff0c;如何优化运营、提升效率&#xff0c;是每个零售商都在关注的问题。电子价签作为一项创新技术&#xff0c;提供了蒿效的解决方案。今天&#xff0c;我们就来聊聊电子价签如何帮助零售商轻松管理信息、减少人工误差&#xff0c;并展示它在门…

Electron构建桌面应用程序,服务于项目的自主学习记录(持续更新...

无所畏惧地面对未知&#xff0c;并将其视为成长的机会 大纲官网快速入门1.安装node.js -- 这里推荐用nvm管理2.脚手架创建3.electron 包安装到应用的开发依赖4.创建主进程(main.js)并启动项目1.创建页面2.配置main.js3.启动项目 -- 效果 进阶 -- 基于项目场景功能使用场景一&am…

自动猫砂盆有必要买吗?2024年热门风大的自动猫砂盆测评分享!

自动猫砂盆不知道大家尝试过没&#xff0c;就是可以自动给猫咪铲屎的神器东西&#xff0c;而且它能把那些猫屎都集中收集起来&#xff0c;我们这种上班忙碌的人一回家就能收获一个干干净净的猫砂盆&#xff0c;别提有多快乐了。就算出差都不怕&#xff0c;三四天不回来都只用扔…

红黑树源代码(进阶与细节解释)

目录 对于结点的修改 红黑树模板参数的控制 红黑树结点当中存储的数据 对于insert函数的细节修改 迭代器的代码 迭代器类的添加 迭代器的 迭代器的-- 正向迭代器的代码 红黑树代码全部展示&#xff1a; 看完前两篇的文章&#xff0c;相信对于红黑树有了一定的了解&…

飘香水果购物网站:基于SpringBoot的架构设计

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常适…

【C++】模拟实现hash_table(哈希表)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:实战项目集 ⚙️操作环境:Visual Studio 2022 目录 一.了解项目功能 二.逐步实现项目功能模块及其逻辑详解 &#x1f4cc;实现HashNode类模板 &#x1f38f;构造HashNode类成员变量 &#x1f38f;实现HashNode类构造函数…

家里养有宠物应该用哪款宠物空气净化器比较好?哪款最能吸毛?

这不是国庆节刚过吗&#xff0c;我的小猫终于是平安的度过了在农村生活的时光&#xff0c;之前还担心会不会被爸妈嫌弃&#xff0c;这下好了&#xff0c;嫌弃也过了国庆节。 但是一把猫咪带回出租房&#xff0c;由于几天不在房子里待&#xff0c;猫咪对熟悉的环境又特别激动&a…

视频怎么做成扫码展示?视频二维码在线做的方法

视频想要快速的分享给其他人&#xff0c;选择生成二维码是一种很方便的形式&#xff0c;其他人只需要扫描二维码就可以在线查看视频&#xff0c;与其他分享方式相比更加的简单、方便。现在日常生活中有很多场景都会有视频二维码的应用&#xff0c;简化了获取视频的流程&#xf…

JavaEE: 深入解析HTTP协议的奥秘(3)

文章目录 HTTP认识 "报头"(Header)认识 "状态码"(status code) HTTP JavaEE: 深入解析HTTP协议的奥秘(2) 书接上文~ 认识 “报头”(Header) Header 的整体的格式是"键值对"结构. 每个键值对占一行,键和值之间使用分号分隔. Host 表示服务器主…

【基础篇】一个键值数据库包含什么?

背景 今天&#xff0c;在构造这个简单的键值数据库时&#xff0c;我们只需要关注整体架构和核心模块。这就相当于医学上在正式解剖人体之前&#xff0c;会先解剖一只小白鼠。我们通过剖析这个最简单的键值数据库&#xff0c;来迅速抓住学习和调优 Redis 的关键。 我们把这个简…

STM32外设应用知识详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

RKMEDIA画面质量调节-QP调节

QP是在视频采集编码过程中的量化参数&#xff0c;其值与画面质量成反比&#xff0c;即QP值越大画面质量越小&#xff0c;其具体调整方法如下&#xff1a; typedef struct rkVENC_RC_PARAM_S {RK_U32 u32ThrdI[RC_TEXTURE_THR_SIZE]; // [0, 255]RK_U32 u32ThrdP[RC_TEXTURE_TH…

如何基于 RLHF 来优化 ChatGPT 类型的大语言模型

&#x1f6b4;前言 对于ChatGPT来说&#xff0c;RLHF是其训练的核心。所谓RLHF&#xff0c;即Reinforcement Learning with Human Feedback&#xff0c;基于人类反馈的强化学习。这项技术通过结合模型自身的生成能力和人类专家的反馈&#xff0c;为改进文本生成质量提供了新的…

解决Android Studio中使用lombok插件错误: 找不到符号的问题

问题 主要是想节省实体类的set、get等方法&#xff0c;使用lombok报错如下&#xff1a; 解决方案 由于Android的限制&#xff0c;在Android中使用lombok兼容极其麻烦&#xff0c;如果你只是想减少set、get等代码可以直接使用kotlin的data class 示例 data class KotlinTes…

等级保护等保资料原件合集(word源资料)

第二章 系统定级与安全域 2.1 系统定级 2.1.1 不同等级的安全保护能力 2.1.2 重要信息系统 2.1.3 定级参考 2.2 安全域定义 2.2.1 安全域定义方法 2.2.2 安全域等级描述 第三章 实施方案设计 3.1 三级等保要求 3.2 基本要求的详细技术要求 3.2.1 物理安全 3.2.2 网…

Unity 从零开始的框架搭建1-1 unity中对象调用的三种方式的优缺点分析【干货】

该文章专栏是向QFrameWork作者凉鞋老师学习总结得来&#xff0c;吃水不忘打井人&#xff0c;不胜感激 Unity 框架搭建学习笔记1-1&#xff0c;前一个1代表凉鞋的第一季教程&#xff0c;后一个1代表该季第一篇我的文章 unity中对象调用的三种方式 方法调用&#xff0c;例如&…

Qt设计登录界面

优化登录框&#xff1a; 将两个按钮连接到槽函数 在构造函数中定义 connect(this->btn1,&QPushButton::clicked,this,&Logon::my_slot);connect(this->btn2,&QPushButton::clicked,this,&Logon::my_cancel); 定义登录按钮连接的槽函数 void Logon::my…

基于Java语言的充电桩平台+云快充协议+充电桩管理后台+充电桩小程序

软件架构 1、提供云快充底层桩直连协议&#xff0c;版本为云快充1.5&#xff0c;对于没有对接过充电桩系统的开发者尤为合适&#xff1b; 2、包含&#xff1a;启动充电、结束充电、充电中实时数据获取、报文解析、Netty通讯框架、包解析工具、调试器模拟器软件等&#xff1b;…