内核LED驱动框架讲解以及led设备注册示例代码

2023-10-27

1、驱动框架介绍

(1)内核中驱动部分维护者针对每个种类的驱动设计一套成熟的、标准的、典型的驱动实现,然后把不同厂家的同类硬件驱动中相同的部分抽出来自己实现好,再把不同部分留出接口给具体的驱动开发工程师来实现,这就叫驱动框架。
(2)内核维护者在内核中设计了一些统一管控系统资源的体系,这些体系让内核能够对资源在各个驱动之间的使用统一协调和分配,保证整个内核的稳定健康运行。譬如系统中所有的GPIO就属于系统资源,每个驱动模块如果要使用某个GPIO就要先调用特殊的接口先申请,申请到后使用,使用完后要释放。
(3)一些特定的接口函数、一些特定的数据结构,这些是驱动框架的直接表现。

2、LED框架相关文件

(1)drivers/leds目录,这个目录就是驱动框架规定的LED这种硬件的驱动源码放的路径。
(2)led-class.c和led-core.c,这两个文件加起来属于LED驱动框架的第一部分,这两个文件是内核开发者提供的,他们描述的是内核中所有厂家的不同LED硬件的相同部分的逻辑。
(3)leds-xxxx.c,这个文件是LED驱动框架的第2部分,是由不同厂商的驱动工程师编写添加的,厂商驱动工程师结合自己公司的硬件的不同情况来对LED进行操作,使用第一部分提供的接口来和驱动框架
进行交互,最终实现驱动的功能。

3、LED框架分析

3.1、内核支持LED框架

make menuconfig
	Device Drivers 
		LED Support
			LED Class Support #选择y或者m

(1)执行"make menuconfig"命令,一般选择"LED Class Support"为y,直接编译进内核;选择为y会后,再次编译内核就会把led-class.c编译进内核;
(2)或者直接去修改内核配置文件的"CONFIG_LEDS_CLASS=y"配置项;

3.2、LED框架的加载和卸载

//导出LED驱动的注册/卸载函数
EXPORT_SYMBOL_GPL(led_classdev_register);
EXPORT_SYMBOL_GPL(led_classdev_unregister);

static int __init leds_init(void)
{
	leds_class = class_create(THIS_MODULE, "leds");	//创建"leds"设备类
	if (IS_ERR(leds_class))
		return PTR_ERR(leds_class);
	leds_class->suspend = led_suspend;	//设备休眠的函数指针
	leds_class->resume = led_resume;	//设备唤醒的函数指针
	leds_class->dev_attrs = led_class_attrs;//初始化设备属性
	return 0;
}

static void __exit leds_exit(void)
{
	class_destroy(leds_class);	//销毁"leds"设备类
}

subsys_initcall(leds_init); //加载LED框架
module_exit(leds_exit);	//卸载LED框架

(1)LED框架的代码和一本的字符驱动几乎一样,既可以编译进内核又可以单独编译成ko文件,但是需要注意驱动的加载函数用subsys_initcall宏声明;
(2)我们利用LED驱动框架写led驱动,就是利用led_classdev_register()函数来注册一个驱动,重点是理解led_classdev_register()函数;

3.3、subsys_initcall宏

	#define subsys_initcall(fn)		__define_initcall("4",fn,4)
	
	subsys_initcall(leds_init);

(1)效果:把leds_init函数放到".initcall4.init"段,具体宏分析参考:《内核加载驱动机制详解(module_init & module_exit)》
(2)我们自己编写的LED驱动加载时用"module_init"宏,这样我们的LED驱动代码会被放在".initcall6.init"段;
(3)“.initcall4.init"段会比”.initcall6.init"段先加载,而我们写的LED驱动代码是依赖内核的LED框架的,所以内核LED框架被先加载也是必须的;

3.4、struct class结构体和struct device_attribute结构体

参考博客:《struct class结构体》

3.5、内核LED框架创建leds类

/* interface for exporting device attributes */
struct device_attribute {
	struct attribute	attr;
	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
			char *buf);
	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count);
};

static struct device_attribute led_class_attrs[] = {
	__ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
	__ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
#ifdef CONFIG_LEDS_TRIGGERS
	__ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
#endif
	__ATTR_NULL,
};

在这里插入图片描述

(1)在leds_init()创建leds类时,将led_class_attrs变量赋予leds_class->dev_attrs,作为类的设备属性;
(2)效果:每一个创建的属于LED类的设备,在设备文件夹下面都会有brightness、max_brightness、trigger文件,在读取这些文件时调用对应的show方法,在写入这些文件时调用store方法,如果对应的show/store方法是NULL,则不支持读取/写入;
(3)brightness:用来控制亮度;max_brightness:保存允许的最大亮度;trigger:触发方式;

4.用LED框架注册led设备

4.1、注册和卸载接口

int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
	led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
				      "%s", led_cdev->name);

	······
	return 0;
}
EXPORT_SYMBOL_GPL(led_classdev_register);

void led_classdev_unregister(struct led_classdev *led_cdev)
{
	······

	device_unregister(led_cdev->dev);
	······
}
EXPORT_SYMBOL_GPL(led_classdev_unregister);

(1)LED框架中导出了led_classdev_register()函数和led_classdev_unregister()函数,给我们注册led驱动;
(2)注册接口:主要功能就是调用device_create()函数在leds类下面创建名字为led_cdev->name的设备;
(3)卸载接口:主要功能就是调用device_unregister()函数注销之前注册驱动时创建的设备;
总结:注册led驱动的重点就是构建注册接口led_classdev_register()函数需要的struct led_classdev结构体;

4.2、struct led_classdev结构体

struct led_classdev {
	const char		*name;	//将来在/sys/class/leds/目录下,创建名字为name的设备
	int			 brightness;	//led设备的亮度
	int			 max_brightness;	//led设备的最大亮度
	int			 flags;				//led设备的标志位

	void		(*brightness_set)(struct led_classdev *led_cdev,
					  enum led_brightness brightness);	//设置led设备亮度的方法

	enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);	//获取led设备亮度的方法

	struct device		*dev;	//设备结构体,用来在内核中表示设备
	struct list_head	 node;			/* LED Device list */
	······
};

(1)上面是结构体的部分成员变量,在LED框架中,就是用struct led_classdev结构体来描述一个led设备;
(2)如何填充struct led_classdev结构体是注册led设备的重点;

4.3、怎么添加自己的LED驱动

在这里插入图片描述

红框里的就是之前别人添加好的LED驱动代码,我们只需要仿造别人的添加过程去添加自己的驱动代码;
大致步骤:
(1)将自己的led驱动源码文件放到kernel/drivers/leds目录下;
(2)在kernel/drivers/leds目录的Makefile和Kconfig文件中支持我们新添加的驱动源文件;

5、用LED驱动框架注册led设备的示例代码分析

参考博客:《用LED驱动框架注册led设备的示例代码》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

内核LED驱动框架讲解以及led设备注册示例代码 的相关文章

  • 嵌入式内核及驱动开发中级(上)

    目录 第一部分 一 设备分类 设备申请和注销 一 Linux内核对设备的分类 二 设备号 内核中同类设备的区分 三 申请和注销设备号 二 Code exerccise 三 知识补充 第二部分 一 函数指针复习 一 函数指针复习 1 1 内存
  • GPIO 模拟SPI

    GPIO 模拟SPI SPI简介 SCPH 0 SCPOL 0 的 SPI 协议时序图 在这里插入图片描述 https img blog csdnimg cn daeedeab80d14239aa1331736b17bf7d png SCP
  • 内核hwmon驱动框架详解以及海思芯片温度驱动分析

    1 hwmon驱动框架介绍 hwmon即hardware monitoring framework 硬件监视框架 可以把温度传感器 风扇 电源管理等设备的驱动都利用hwmon框架去实现 在设备的归类上比较容易理解 2 hwmon驱动框架分析
  • Linux驱动(一)之最简单的驱动程序

    1 前言 为什么要有驱动 为了防止像我等小菜程序员写应用程序的时候权限过高直接去操作底层设备 给设备造成不可挽回的损失 所以要过度一下 让大牛们将底层封装好 应用开发工程师只需要通过特定的接口来完成特定的功能就可以了 2 应用 通常情况下
  • mesa调试技巧

    技术关键字 mesa log系统 环境变量 目录 前言 一 gdb或vscode的断点调试 二 mesa log 系统的使用 总结 前言 软件调试技术是要求软件开发人员必备的一项技能 不同的问题具有不同的调试手段和方法 本文从mesa库的实
  • Linux驱动:应用程序open如何调用到驱动程序的open函数

    字符设备文件的打开流程 相关结构体 流程涉及相关结构体如下 struct inode dev t i rdev const struct file operations i fop former gt i op gt default fil
  • Linux设备驱动的软件架构思想与设备驱动的基础内容总结

    Linux设备驱动的软件架构思想与设备驱动的基础内容总结 Linux是一个兼容性特别强的一个系统 而兼容性的实现与驱动强大的适应性密不可分 而这个具体的实现是离不开 总线bus和类class的管理方式 Linux使用bus统一的管理一系列相
  • Linux 块设备驱动实验

    一 块设备驱动要远比字符设备驱动复杂得多 不同类型的存储设备又对应不同的驱动子系统 本章我们重点学习一下块设备相关驱动概念 不涉及到具体的存储设备 1 什么是块设备 块设备是针对存储设备的 比如 SD 卡 EMMC NAND Flash N
  • Linux驱动开发--平台总线id和设备树匹配

    目录 一 ID匹配之框架代码 二 ID匹配之led驱动 三 设备树匹配 四 设备树匹配之led驱动 五 一个编写驱动用的宏 一 ID匹配之框架代码 id匹配 可想象成八字匹配 一个驱动可以对应多个设备 优先级次低 注意事项 device模块
  • 内核中时间相关的知识介绍

    1 内核要解决的时间相关问题 1 如何度量时间差 如何比较时间 2 如何获取当前时间 3 如何将操作延迟指定的一段时间 4 如何调度异步函数到指定的时间之后执行 2 度量时间差 2 1 内核度量时间的原理 1 Soc有时间相关的硬件 比如定
  • keil C51 常见错误和警告

    C51编译器识别错类型有三种 1 致命错误 伪指令控制行有错 访问不存在的原文件或头文件等 2 语法及语义错误 语法和语义错误都发生在原文件中 有这类错误时 给出 提示但不产生目标文件 错误超过一定数量才终止编译 3 警告 警告出现并不影响
  • Linux INPUT 子系统实验

    目录 input 子系统 input 子系统简 input 驱动编写流程 input event 结构体 硬件原理图分析 实验程序编写 修改设备树文件 按键input 驱动程序编写 编写测试APP 运行测试 编译驱动程序和测试APP 运行测
  • Macronix MX25L25645G NOR Flash无法擦除问题分析

    1 问题现象描述 处理器使用的 SAM9X60 使用的内核版本是 5 10 80 在调试 Macronix MX25L25645G NOR Flash时 发现flash驱动加载成功后 使用 mtd debug 工具 erase flash时
  • inux字符驱动之read、write部分

    本期主题 linux字符驱动之read write部分 往期链接 linux设备驱动中的并发 linux设备驱动中的编译乱序和执行乱序 linux设备驱动之内核模块 linux字符驱动 linux字符驱动之ioctl部分 linux字符驱动
  • 嵌入式开发--SPI介绍和驱动开发

    目录 一 通信总线SPI介绍 二 SPI时序介绍和工作模式 三 基于stm32的spi初始化步骤 一 通信总线SPI介绍 SPI 全称为Serial Peripheral Interface 是一种同步的串行通信协议 SPI协议最初由Mot
  • 自举电路原理

    文章目录 一 自举电路核心原理 二 为什么要自举升压 三 简单的自举电路模型 四 自举电路在高电压栅极驱动电路中的应用 1 MOS管Q开通时 2 MOS管Q关断时 一 自举电路核心原理 电容两端电压不能突变 根据电容公式 i t C du
  • 使用 Microchip SAM9X60 OTP 存储板卡的MAC地址和序列号

    1 介绍 SAM9X60 处理器有部分OTP One Time Programming Aera 可用于存储user data 这样的话我们就可以将板卡 MAC Address和 SN 序列号写到固定的OTP User Area中 为什么要
  • Linux驱动

    Linux驱动入门系列 Linux驱动入门 一 字符设备驱动基础 Linux驱动入门 二 操作硬件 Linux驱动入门 三 Led驱动 Linux驱动入门 四 非阻塞方式实现按键驱动 Linux驱动入门 五 阻塞方式实现按键驱动 Linux
  • LCD笔记(4)分析内核自带的LCD驱动程序

    1 驱动程序框架 Linux驱动程序 驱动程序框架 硬件编程 在前面已经基于QEMU编写了LCD驱动程序 对LCD驱动程序的框架已经分析清楚 核心就是 分配fb info 设置fb info 注册fb info 硬件相关的设置 1 1 入口
  • OpenHarmony基于HDF简单驱动开发实例

    背景 OpenHarmony 3 0 LTS qemu small system demo liteos a qemu 添加配置 device qemu arm virt liteos a hdf config device info de

随机推荐

  • 找出一个无序数组的中位数

    要解决这个问题首先要了解什仫是中位数 所谓的中位数就是在一组有序的数字中找到中间的那个数字 如果数字的个数是奇数则直接返回中间的那个数 如果数字的个数是偶数此时这组数据的中位数有两个 取中间两个数的平均值即可 想法一 不论用什仫排序算法使得
  • flutter android 和 ios 发布

    android篇 keytool genkey v alias android keyalg RSA validity 20000 keystore Users 当前用户的用户名 android keystore keytool genke
  • Web学习之JavaScript

    文章目录 一 什么是JavaScript 二 JavaScript 用法 三 Chrome 浏览器中执行 JavaScript 四 JavaScript 语法 五 JavaScript 语句 六 JavaScript 函数 七 JavaSc
  • 【redis】单机安装部署redis7.0版本

    下面我以redis 7 0 5版本 来进行讲解 链接 https pan baidu com s 1FesU8iHJQyW4pVARIqeQAA 提取码 qtqc 单机安装Redis 1 首先需要安装Redis所需要的依赖 yum inst
  • 预测知识

    预测知识 预测技术流程及模型评价 目录 预测知识 预测技术流程及模型评价 神经网络 机器学习 深度学习 参考资料 神经网络 神经网络 neural network 是机器学习的一个重要分支 也是深度学习的核心算法 神经网络的名字和结构 源自
  • 上传图片几种方式解析(上)--file

    浏览器上传图片到服务器时通过input type file 以及onchange事件的配合实现的 element和vant的ui库的图片上传都是基于这个 input的files属性 1 众所周知 一级dom事件不同于addeventlisn
  • c语言三目运算符的一些小细节,赋值不改变变量的值

    C语言三目运算符的一些小细节 赋值不改变变量的值 今天无聊翻翻C语言的课本 看到三目运算符的时候 心想这个和if else 语句用法一样 突然脑海里浮现一个想法 三目运算符结构 表达式1 表达式2 表达式3 表达式1 为逻辑表达式 如果为真
  • 使用左、右、全、内连接及使用where条件语句的区别

    使用左 右 全 内连接及使用 where 条件语句的区别 从学SQL语句到现在 从来没有使用过左右连接 也许会有人感到惊讶 但是确实是没有 因为我一直是使用的WHERE条件语句 我也想试一下效果 今天做了一下测试 终于知道 WHERE 条件
  • MySQL --- 多表查询

    多表查询 事务 以及提升查询效率最有手段的索引 一 多表查询 1 1 多表查询 概述 1 1 1 数据准备 将资料中准备好的多表查询数据准备的SQL脚本导入数据库中 部门表 员工表 1 1 2 介绍 多表查询 指从多张表中查询数据 就是从多
  • 系统架构设计师(第二版)学习笔记----信息安全基础知识

    原文链接 系统架构设计师 第二版 学习笔记 信息系统基础 文章目录 一 信息安全的概念 1 1 信息安全的基本要素 1 2 信息安全的内容 1 3 设备安全的内容 1 4 数据安全的内容 1 5 内容安全的含义 1 6 行为安全的含义 二
  • Python函数常见return返回值类型

    Python函数常见return返回值类型Python函数return返回值类型主要包括 class int class str class tuple class list class dict class bool class None
  • 小明和小强的故事 漫画版

    转载于 https blog 51cto com loofeer 676484
  • 发送arp请求报文

    1 报文格式 2 代码如下 include
  • Python爬虫入门教程(非常详细)

    初学Python之爬虫的简单入门 一 什么是爬虫 1 简单介绍爬虫 爬虫的全称为网络爬虫 简称爬虫 别名有网络机器人 网络蜘蛛等等 网络爬虫是一种自动获取网页内容的程序 为搜索引擎提供了重要的数据支撑 搜索引擎通过网络爬虫技术 将互联网中丰
  • C# 计算两个日期之间的所有日期

    用一个for循环就可以解决 int year Begin Convert ToInt32 this dateBegin Value ToString yyyy int month Begin Convert ToInt32 this dat
  • 解决英文版windows10安装软件中文显示乱码问题

    实验室买了台Thorlabs的设备 配了一台笔记本 带的操作系统是美版的windows10 为了提高笔记本的利用率嘛就在这台笔记本安装了一些中文软件 结果问题就出现了 安装完某些中文软件 能正常打开也能正常操作就是显示的中文乱码 在网上找了
  • [SPSS]系统聚类和kmeans聚类的spss实现——基于多维度对中国各城市聚类

    一 系统聚类 选中系统聚类并把变量移入变量框内 聚类选择按照个案聚类 在Display栏中选择Statistics和Plots复选框 这样在结果输出窗口中可以同时得到聚类结果统计量和统计图 选中绘图中的谱系图 单击保存选项卡 方案范围选择2
  • 教你用go 配置管理神器Viper解析docker-compose文件

    什么是Viper Viper 是一个完整的 Go 应用程序配置解决方案 包括 12 Factor 应用程序 它被设计为在应用程序中工作 并且可以处理所有类型的配置需求和格式 它支持 设置默认值 从 JSON TOML YAML HCL en
  • 后台程序 报错内容:java.sql.SQLException: Java heap space

    原因有以下可能 1 查询没有通过参数 而是直接查询出所有的记录 2 是由于mysql单个字段存储的内容过大导致堆内存溢出 3 JVM启动时 JVM堆会自动设置heap size值 值太小导致
  • 内核LED驱动框架讲解以及led设备注册示例代码

    1 驱动框架介绍 1 内核中驱动部分维护者针对每个种类的驱动设计一套成熟的 标准的 典型的驱动实现 然后把不同厂家的同类硬件驱动中相同的部分抽出来自己实现好 再把不同部分留出接口给具体的驱动开发工程师来实现 这就叫驱动框架 2 内核维护者在